From 8d31e3520f6a0d96517bdbc318011deb79c65275 Mon Sep 17 00:00:00 2001 From: Doug A Date: Wed, 22 Jul 2026 12:53:02 -0400 Subject: [PATCH 1/2] more iterations --- .../hda_flowsheet_with_costing.ipynb | 1867 ++++- .../hda_flowsheet_with_costing_doc.ipynb | 4111 +++++----- .../hda_flowsheet_with_costing_test.ipynb | 2939 ++++++-- .../hda_flowsheet_with_costing_usr.ipynb | 2939 ++++++-- .../docs/flowsheets/methanol_synthesis.ipynb | 1220 +-- .../flowsheets/methanol_synthesis_doc.ipynb | 6377 ++++++---------- .../flowsheets/methanol_synthesis_test.ipynb | 6641 ++++++----------- .../flowsheets/methanol_synthesis_usr.ipynb | 6364 ++++++---------- .../notebooks/docs/tut/core/hda_flowsheet.py | 1227 ++- .../docs/tut/core/hda_flowsheet_doc.ipynb | 3760 +++++----- .../docs/tut/core/hda_flowsheet_test.ipynb | 4492 +++++------ 11 files changed, 21395 insertions(+), 20542 deletions(-) diff --git a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing.ipynb b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing.ipynb index d35b99bc..9b6cc234 100644 --- a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "tags": [ "header", @@ -97,11 +97,459 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "fs.s03\n", + "fs.H101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n", + "2026-07-22 11:48:38 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "Solving flowsheet...\n", + "\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=5000\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1031\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 934\n", + "\n", + "Total number of variables............................: 340\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 146\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 340\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.60e+04 0.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 8.69e+03 1.42e+03 -1.0 2.00e+04 - 9.71e-01 4.67e-01H 1\n", + " 2 0.0000000e+00 3.05e+03 1.56e+03 -1.0 1.60e+04 - 9.79e-01 4.90e-01h 1\n", + " 3 0.0000000e+00 1.58e+03 1.55e+05 -1.0 1.40e+04 - 9.90e-01 4.99e-01h 1\n", + " 4 0.0000000e+00 5.49e+02 8.87e+08 -1.0 8.42e+03 - 1.00e+00 9.57e-01h 1\n", + " 5 0.0000000e+00 4.25e+03 2.87e+10 -1.0 8.02e+02 - 1.00e+00 9.90e-01h 1\n", + " 6 0.0000000e+00 2.25e+03 1.51e+10 -1.0 8.39e+00 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 2.27e+01 1.40e+08 -1.0 2.45e-03 - 1.00e+00 1.00e+00f 1\n", + " 8 0.0000000e+00 2.45e-03 1.23e+04 -1.0 2.39e-05 - 1.00e+00 1.00e+00h 1\n", + " 9 0.0000000e+00 2.24e-08 4.65e-01 -2.5 9.06e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 0.0000000e+00 2.24e-08 1.41e+05 -5.7 1.38e-07 - 1.00e+00 5.00e-01h 2\n", + " 11 0.0000000e+00 7.45e-09 5.56e-03 -5.7 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 12 0.0000000e+00 7.45e-09 2.47e-09 -5.7 9.00e-08 - 1.00e+00 1.00e+00h 1\n", + " 13 0.0000000e+00 2.24e-08 5.06e-07 -7.0 1.38e-07 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 13\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "Constraint violation....: 5.8207660913467407e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593319938534624e-14 2.8593319938534624e-14\n", + "Complementarity.........: 9.0909090909115134e-08 9.0909090909115134e-08\n", + "Overall NLP error.......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "\n", + "\n", + "Number of objective function evaluations = 17\n", + "Number of objective gradient evaluations = 14\n", + "Number of equality constraint evaluations = 17\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 14\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 13\n", + "Total seconds in IPOPT = 0.018\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Complete.\n", + "\n" + ] + } + ], "source": [ "# Source file for prebuilt flowsheets\n", "from hda_flowsheets_for_costing_notebook import hda_with_flash\n", @@ -132,7 +580,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -161,7 +609,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -206,7 +654,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -237,7 +685,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -303,14 +751,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ - "# Eefine solver\n", + "# Define solver\n", "from idaes.core.solvers import get_solver\n", "\n", - "solver = get_solver()\n", + "solver = get_solver(\"ipopt_v2\", options={\"max_iter\": 500})\n", "\n", "# Check that the degrees of freedom is zero\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", @@ -320,9 +768,283 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.14.20: linear_solver=\"ma57\"\n", + "max_iter=500\n", + "nlp_scaling_method=\"gradient-based\"\n", + "tol=1e-06\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 604\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 569\n", + "\n", + "Total number of variables............................: 160\n", + " variables with only lower bounds: 10\n", + " variables with lower and upper bounds: 38\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 160\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.00e+05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (6534)\n", + " 1 0.0000000e+00 8.81e+04 5.45e+03 -1.0 9.27e+04 - 2.62e-01 1.20e-01h 1\n", + " 2 0.0000000e+00 6.34e+04 2.46e+03 -1.0 8.16e+04 - 9.83e-01 2.87e-01h 1\n", + " 3 0.0000000e+00 3.40e+04 1.76e+03 -1.0 5.81e+04 - 4.59e-01 4.86e-01h 1\n", + " 4 0.0000000e+00 2.33e+04 9.17e+04 -1.0 2.99e+04 - 7.04e-01 5.09e-01h 1\n", + " 5 0.0000000e+00 1.13e+04 7.52e+08 -1.0 1.47e+04 - 8.02e-01 9.65e-01h 1\n", + "Reallocating memory for MA57: lfact (7452)\n", + " 6 0.0000000e+00 5.50e+03 3.83e+08 -1.0 8.18e+02 - 9.90e-01 6.10e-01h 1\n", + " 7 0.0000000e+00 5.23e+03 3.45e+08 -1.0 3.84e+02 - 1.00e+00 5.07e-02h 1\n", + "Reallocating memory for MA57: lfact (8076)\n", + " 8 0.0000000e+00 5.22e+03 7.30e+08 -1.0 3.70e+02 - 1.00e+00 5.85e-04h 1\n", + " 9r 0.0000000e+00 5.22e+03 1.00e+03 2.3 0.00e+00 - 0.00e+00 3.66e-07R 5\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10r 0.0000000e+00 6.37e+04 2.29e+04 2.3 2.43e+07 - 1.50e-03 9.91e-04f 1\n", + " 11r 0.0000000e+00 1.51e+04 1.09e+05 2.3 2.98e+07 - 1.34e-01 2.58e-03f 1\n", + " 12r 0.0000000e+00 3.92e+04 1.08e+05 2.3 8.59e+07 - 8.37e-03 1.46e-02f 1\n", + " 13r 0.0000000e+00 1.67e+05 1.08e+05 2.3 5.23e+06 - 5.83e-03 9.06e-02f 1\n", + " 14r 0.0000000e+00 4.67e+05 1.05e+05 2.3 1.18e+07 - 2.42e-02 9.08e-02f 1\n", + " 15r 0.0000000e+00 4.64e+05 1.05e+05 2.3 5.75e+06 - 1.97e-03 6.57e-03h 1\n", + " 16r 0.0000000e+00 4.63e+05 9.23e+04 2.3 1.50e+04 -4.0 1.25e-01 1.34e-03h 1\n", + " 17r 0.0000000e+00 6.08e+05 8.46e+04 2.3 5.32e+06 - 8.37e-02 3.04e-01f 1\n", + " 18r 0.0000000e+00 5.71e+05 5.77e+04 2.3 1.87e+06 - 3.20e-01 1.38e-01f 1\n", + " 19r 0.0000000e+00 4.10e+05 5.27e+04 2.3 4.12e+06 - 9.00e-02 3.37e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r 0.0000000e+00 3.86e+05 4.93e+04 2.3 1.63e+04 -3.6 6.50e-02 5.85e-02f 1\n", + " 21r 0.0000000e+00 3.60e+05 4.51e+04 2.3 7.48e+03 -3.1 8.38e-02 6.63e-02h 1\n", + " 22r 0.0000000e+00 3.64e+05 4.08e+04 2.3 4.06e+06 - 9.58e-02 7.04e-02f 1\n", + " 23r 0.0000000e+00 3.86e+05 1.88e+05 2.3 5.59e+06 - 1.68e-01 1.49e-01f 1\n", + " 24r 0.0000000e+00 3.86e+05 1.88e+05 2.3 1.12e+02 4.7 1.81e-03 1.57e-03h 1\n", + " 25r 0.0000000e+00 3.86e+05 1.91e+05 2.3 1.55e+02 4.2 2.71e-03 1.11e-03h 1\n", + " 26r 0.0000000e+00 3.85e+05 1.86e+05 2.3 1.56e+02 3.7 8.21e-04 3.62e-03h 1\n", + " 27r 0.0000000e+00 3.85e+05 3.16e+05 2.3 1.55e+02 5.1 1.83e-02 6.41e-04h 1\n", + " 28r 0.0000000e+00 3.82e+05 3.30e+05 2.3 1.55e+02 4.6 1.40e-02 1.11e-02h 1\n", + " 29r 0.0000000e+00 3.81e+05 7.08e+05 2.3 1.53e+02 5.0 2.85e-02 4.20e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30r 0.0000000e+00 3.72e+05 7.46e+05 2.3 1.53e+02 4.5 4.86e-02 3.45e-02h 1\n", + " 31r 0.0000000e+00 3.67e+05 1.89e+06 2.3 1.47e+02 5.0 1.12e-01 2.04e-02h 1\n", + " 32r 0.0000000e+00 3.24e+05 1.59e+06 2.3 1.44e+02 4.5 1.96e-01 1.79e-01h 1\n", + " 33r 0.0000000e+00 3.23e+05 1.58e+06 2.3 1.19e+02 4.0 4.52e-03 5.61e-03h 1\n", + " 34r 0.0000000e+00 2.94e+05 1.59e+06 2.3 1.18e+02 4.4 3.45e-01 1.47e-01h 1\n", + " 35r 0.0000000e+00 2.80e+05 1.53e+06 2.3 1.01e+02 4.0 1.38e-01 8.76e-02h 1\n", + " 36r 0.0000000e+00 2.52e+05 1.66e+06 2.3 9.17e+01 4.4 3.38e-01 1.83e-01h 1\n", + " 37r 0.0000000e+00 2.39e+05 1.55e+06 2.3 7.50e+01 3.9 9.13e-01 1.05e-01h 1\n", + " 38r 0.0000000e+00 2.13e+05 1.24e+06 2.3 6.72e+01 3.4 5.58e-01 2.28e-01h 1\n", + " 39r 0.0000000e+00 1.95e+05 1.05e+06 2.3 5.18e+01 3.9 1.00e+00 2.15e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40r 0.0000000e+00 1.28e+05 2.34e+05 2.3 4.08e+01 3.4 5.49e-01 1.00e+00h 1\n", + " 41r 0.0000000e+00 1.28e+05 2.87e+05 2.3 8.85e-01 2.9 5.24e-01 9.02e-01f 1\n", + " 42r 0.0000000e+00 1.28e+05 1.76e+05 2.3 3.90e-01 4.2 3.08e-01 9.59e-01f 1\n", + " 43r 0.0000000e+00 1.28e+05 5.03e+04 2.3 1.25e-01 3.8 3.19e-01 1.00e+00f 1\n", + " 44r 0.0000000e+00 1.28e+05 4.94e+04 2.3 4.82e+00 3.3 1.85e-02 1.19e-01f 2\n", + " 45r 0.0000000e+00 1.28e+05 1.37e+04 2.3 3.62e-01 3.7 8.33e-01 1.00e+00f 1\n", + " 46r 0.0000000e+00 1.28e+05 7.07e+03 1.6 5.21e-01 3.2 8.97e-01 1.00e+00f 1\n", + " 47r 0.0000000e+00 1.29e+05 5.44e+02 1.6 9.53e-01 2.8 8.34e-01 8.12e-01f 1\n", + " 48r 0.0000000e+00 1.29e+05 8.91e+02 0.9 2.85e+00 2.3 4.12e-01 2.43e-01f 1\n", + " 49r 0.0000000e+00 1.30e+05 6.99e+02 0.9 8.46e+00 1.8 7.74e-01 2.05e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50r 0.0000000e+00 1.31e+05 3.95e+04 0.9 2.41e+01 1.3 1.00e+00 1.51e-01f 1\n", + " 51r 0.0000000e+00 1.30e+05 4.66e+04 0.9 7.23e+01 0.8 1.00e+00 5.24e-02f 1\n", + " 52r 0.0000000e+00 1.18e+05 3.45e+04 0.9 2.17e+02 0.4 6.96e-01 1.67e-01f 1\n", + " 53r 0.0000000e+00 1.17e+05 1.74e+04 0.9 6.50e+02 -0.1 1.43e-01 1.50e-02f 1\n", + " 54r 0.0000000e+00 1.17e+05 4.23e+04 0.9 1.94e+03 -0.6 6.50e-01 3.25e-02f 1\n", + " 55r 0.0000000e+00 1.18e+05 5.54e+04 0.9 3.69e+03 -1.1 4.70e-01 9.48e-03f 1\n", + " 56r 0.0000000e+00 1.25e+05 2.75e+04 0.9 1.01e+02 -1.5 7.89e-01 1.78e-01f 1\n", + " 57r 0.0000000e+00 1.28e+05 2.68e+04 0.9 9.57e+01 -2.0 9.34e-01 1.60e-01f 1\n", + " 58r 0.0000000e+00 1.37e+05 5.37e+02 0.9 2.51e+02 -2.5 1.00e+00 6.23e-01f 1\n", + " 59r 0.0000000e+00 1.40e+05 1.78e+04 0.2 7.53e+02 -3.0 4.51e-01 6.22e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60r 0.0000000e+00 1.40e+05 1.99e+03 0.2 2.25e+03 -3.4 6.57e-01 3.90e-01f 1\n", + " 61r 0.0000000e+00 1.40e+05 6.25e+04 0.2 8.45e+02 -3.0 1.00e+00 2.93e-01f 1\n", + " 62r 0.0000000e+00 1.40e+05 4.84e+04 0.2 2.48e+03 -3.5 1.00e+00 2.59e-01f 1\n", + " 63r 0.0000000e+00 1.40e+05 9.09e+04 0.2 8.10e+02 -4.0 5.18e-01 4.12e-02f 1\n", + " 64r 0.0000000e+00 1.40e+05 4.52e+03 0.2 3.19e+02 -3.6 5.90e-01 8.39e-01f 1\n", + " 65r 0.0000000e+00 1.40e+05 9.20e+03 0.2 8.45e+02 -4.0 2.58e-01 3.11e-01f 1\n", + " 66r 0.0000000e+00 1.40e+05 9.35e+02 0.2 2.32e+03 -4.5 9.50e-02 5.05e-01f 1\n", + " 67r 0.0000000e+00 1.40e+05 1.80e+03 0.2 3.94e+03 -5.0 1.00e+00 6.61e-02f 1\n", + " 68r 0.0000000e+00 1.40e+05 2.93e+03 0.2 4.85e+03 -5.5 9.99e-01 2.84e-01f 1\n", + " 69r 0.0000000e+00 1.38e+05 6.05e+03 0.2 6.81e+03 -5.9 1.00e+00 2.40e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70r 0.0000000e+00 1.37e+05 1.78e+03 0.2 2.85e+03 -5.5 1.00e+00 1.00e+00f 1\n", + " 71r 0.0000000e+00 1.34e+05 1.31e+03 0.2 8.14e+03 -6.0 3.19e-01 3.05e-01f 1\n", + " 72r 0.0000000e+00 1.31e+05 1.83e+03 0.2 2.65e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 73r 0.0000000e+00 1.28e+05 3.42e+03 0.2 1.45e+04 -6.0 1.00e+00 2.70e-01f 1\n", + " 74r 0.0000000e+00 1.24e+05 1.09e+01 0.2 4.06e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 75r 0.0000000e+00 1.05e+05 7.56e+03 -0.5 5.64e+04 -6.1 2.15e-01 3.59e-01f 1\n", + " 76r 0.0000000e+00 1.05e+05 1.79e+04 -0.5 2.46e+03 -4.8 5.42e-01 1.26e-01f 1\n", + " 77r 0.0000000e+00 1.05e+05 2.30e+04 -0.5 9.93e+03 -5.2 1.04e-02 6.09e-02f 1\n", + " 78r 0.0000000e+00 1.05e+05 1.44e+03 -0.5 2.90e+03 -4.8 1.16e-01 1.32e-02f 1\n", + " 79r 0.0000000e+00 1.04e+05 8.21e+04 -0.5 9.44e+03 -5.3 4.02e-02 1.19e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80r 0.0000000e+00 1.04e+05 4.46e+03 -0.5 1.93e+03 -4.9 2.08e-01 2.98e-02f 1\n", + " 81r 0.0000000e+00 9.40e+04 1.37e+05 -0.5 1.15e+04 -5.3 5.49e-03 2.67e-01f 1\n", + " 82r 0.0000000e+00 9.39e+04 1.21e+05 -0.5 2.56e+03 -4.9 3.04e-01 9.74e-03f 1\n", + " 83r 0.0000000e+00 9.25e+04 1.08e+05 -0.5 4.97e+03 -5.4 1.59e-01 1.20e-01f 1\n", + " 84r 0.0000000e+00 9.25e+04 1.35e+05 -0.5 8.51e+03 -5.9 5.44e-01 3.08e-02f 1\n", + " 85r 0.0000000e+00 1.04e+05 1.06e+05 -0.5 1.26e+04 -6.3 1.73e-01 4.10e-01f 1\n", + " 86r 0.0000000e+00 1.08e+05 1.45e+05 -0.5 2.50e+04 -6.8 1.23e-01 7.63e-02f 1\n", + " 87r 0.0000000e+00 1.07e+05 1.40e+05 -0.5 4.68e+02 -2.8 3.12e-02 1.16e-01h 1\n", + " 88r 0.0000000e+00 1.07e+05 1.34e+05 -0.5 1.25e+02 -2.4 1.37e-01 6.14e-02h 1\n", + " 89r 0.0000000e+00 1.05e+05 1.21e+05 -0.5 6.38e+01 -1.9 4.82e-02 1.54e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r 0.0000000e+00 1.04e+05 1.11e+05 -0.5 2.62e+01 -1.5 9.28e-02 1.14e-01h 1\n", + " 91r 0.0000000e+00 1.02e+05 8.74e+04 -0.5 2.58e+01 -2.0 1.72e-01 2.50e-01h 1\n", + " 92r 0.0000000e+00 1.02e+05 7.56e+04 -0.5 2.13e+01 -1.6 3.40e-01 1.09e-01f 1\n", + " 93r 0.0000000e+00 1.02e+05 5.81e+04 -0.5 9.06e+00 -2.0 6.37e-01 2.34e-01h 1\n", + " 94r 0.0000000e+00 1.02e+05 3.30e+04 -0.5 2.09e+01 -2.5 1.00e+00 4.49e-01h 1\n", + " 95r 0.0000000e+00 1.01e+05 2.02e+03 -0.5 9.58e+01 -3.0 4.65e-01 8.13e-01f 1\n", + " 96r 0.0000000e+00 1.02e+05 1.56e+04 -0.5 8.77e+01 -3.5 7.24e-01 1.53e-01f 1\n", + " 97r 0.0000000e+00 1.02e+05 5.99e+03 -0.5 2.31e+02 -3.9 3.97e-01 4.89e-01f 1\n", + " 98r 0.0000000e+00 1.04e+05 4.62e+03 -0.5 4.75e+02 -4.4 6.42e-01 1.95e-01f 1\n", + " 99r 0.0000000e+00 1.04e+05 9.76e+02 -0.5 8.15e+02 -4.9 7.06e-01 6.61e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r 0.0000000e+00 1.05e+05 7.45e+03 -0.5 2.44e+03 -5.4 1.00e+00 1.91e-01f 1\n", + " 101r 0.0000000e+00 1.06e+05 1.94e+03 -0.5 7.23e+02 -4.9 1.00e+00 3.62e-01f 1\n", + " 102r 0.0000000e+00 1.07e+05 7.40e+03 -0.5 1.49e+03 -5.4 1.00e+00 4.66e-01f 1\n", + " 103r 0.0000000e+00 1.08e+05 3.03e+03 -0.5 1.66e+03 -5.9 8.96e-01 8.34e-01f 1\n", + " 104r 0.0000000e+00 1.10e+05 5.48e+02 -0.5 9.38e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 105r 0.0000000e+00 1.10e+05 1.76e+02 -0.5 1.46e+03 -6.0 7.45e-01 1.00e+00f 1\n", + " 106r 0.0000000e+00 1.10e+05 7.27e+01 -0.5 6.32e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 107r 0.0000000e+00 1.11e+05 1.41e+03 -0.5 1.49e+03 -6.0 1.00e+00 9.82e-01f 1\n", + " 108r 0.0000000e+00 1.12e+05 1.04e+03 -0.5 3.05e+03 -6.5 1.00e+00 4.21e-01f 1\n", + " 109r 0.0000000e+00 1.12e+05 3.92e+02 -0.5 7.12e+03 -7.0 8.81e-01 5.45e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110r 0.0000000e+00 1.12e+05 6.27e+02 -0.5 1.40e+04 -7.4 1.00e+00 2.04e-01f 1\n", + " 111r 0.0000000e+00 1.27e+05 1.93e+02 -0.5 2.11e+04 -7.9 7.01e-01 6.92e-01f 1\n", + " 112r 0.0000000e+00 1.51e+05 1.49e+02 -0.5 2.24e+04 -8.4 4.24e-01 4.78e-01f 1\n", + " 113r 0.0000000e+00 1.28e+05 1.63e+01 -0.5 2.40e+04 -8.9 1.00e+00 1.00e+00f 1\n", + " 114r 0.0000000e+00 1.36e+05 3.29e+02 -0.5 4.21e+04 -9.3 6.45e-01 1.00e+00f 1\n", + " 115r 0.0000000e+00 5.01e+05 1.31e+03 -0.5 9.66e+04 -9.8 9.22e-01 1.00e+00h 1\n", + " 116r 0.0000000e+00 8.78e+05 4.66e+02 -0.5 2.96e+05 -10.3 9.46e-01 1.00e+00h 1\n", + " 117r 0.0000000e+00 6.70e+04 4.18e+02 -0.5 9.60e+05 -10.8 1.00e+00 1.00e+00h 1\n", + " 118r 0.0000000e+00 5.21e+04 9.75e+02 -0.5 3.82e+06 -11.3 1.00e+00 7.10e-01f 1\n", + " 119r 0.0000000e+00 5.30e+04 9.97e+02 -0.5 9.41e+06 - 8.43e-02 2.44e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120r 0.0000000e+00 5.40e+04 9.62e+02 -0.5 2.95e+06 - 1.00e+00 1.41e-01f 1\n", + " 121r 0.0000000e+00 5.13e+04 5.63e+01 -0.5 1.96e+05 - 1.00e+00 1.00e+00f 1\n", + " 122r 0.0000000e+00 5.06e+04 7.06e-01 -0.5 1.45e+04 - 1.00e+00 1.00e+00h 1\n", + " 123r 0.0000000e+00 4.48e+04 1.60e+01 -2.9 1.41e+04 - 8.33e-01 7.83e-01f 1\n", + " 124r 0.0000000e+00 7.43e+04 1.23e+02 -2.9 1.09e+05 -9.9 1.51e-01 1.14e-01f 1\n", + " 125r 0.0000000e+00 7.21e+04 3.54e+02 -2.9 1.66e+05 - 1.51e-01 3.48e-02h 1\n", + " 126r 0.0000000e+00 4.03e+04 3.48e+02 -2.9 6.43e+04 - 4.59e-01 5.71e-01f 1\n", + " 127r 0.0000000e+00 9.43e+03 9.62e+01 -2.9 2.75e+04 - 5.72e-01 8.74e-01h 1\n", + " 128r 0.0000000e+00 7.66e+03 2.89e+02 -2.9 4.00e+03 - 7.38e-01 1.00e+00h 1\n", + " 129r 0.0000000e+00 8.78e+02 2.90e+01 -2.9 1.50e+03 - 9.18e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 130r 0.0000000e+00 7.37e+02 1.27e+01 -2.9 1.32e+03 - 1.00e+00 1.00e+00h 1\n", + " 131r 0.0000000e+00 3.66e+02 6.41e+00 -2.9 9.22e+02 - 1.00e+00 1.00e+00h 1\n", + " 132r 0.0000000e+00 8.13e+00 2.77e-02 -2.9 6.19e+01 - 1.00e+00 1.00e+00h 1\n", + " 133r 0.0000000e+00 7.03e+03 1.41e+01 -4.3 5.16e+03 - 7.78e-01 7.77e-01f 1\n", + " 134r 0.0000000e+00 5.08e+03 4.30e+02 -4.3 3.71e+03 - 1.00e+00 7.18e-01h 1\n", + " 135r 0.0000000e+00 2.02e+02 2.79e+01 -4.3 6.26e+02 - 1.00e+00 1.00e+00h 1\n", + " 136r 0.0000000e+00 1.50e+01 2.52e+00 -4.3 1.46e+02 - 1.00e+00 1.00e+00h 1\n", + " 137r 0.0000000e+00 8.83e-01 1.86e-02 -4.3 1.27e+01 - 1.00e+00 1.00e+00h 1\n", + " 138r 0.0000000e+00 7.60e-01 3.09e-05 -4.3 1.51e+00 - 1.00e+00 1.00e+00h 1\n", + " 139 0.0000000e+00 7.60e-01 1.08e+06 -1.0 8.24e+02 - 9.89e-01 7.57e-06h 17\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 140 0.0000000e+00 7.60e-01 1.94e+06 -1.0 8.24e+02 - 9.90e-01 1.89e-06h 19\n", + " 141 0.0000000e+00 2.27e+02 9.80e+05 -1.0 8.24e+02 - 4.96e-01 4.96e-01s 21\n", + " 142r 0.0000000e+00 2.27e+02 1.00e+03 -1.0 0.00e+00 - 0.00e+00 0.00e+00R 1\n", + " 143r 0.0000000e+00 2.20e+02 1.07e+04 -1.0 2.63e+04 - 2.05e-01 5.61e-03f 1\n", + " 144r 0.0000000e+00 2.03e+03 1.87e+03 -1.0 2.78e+04 - 9.30e-01 2.21e-01f 1\n", + " 145r 0.0000000e+00 1.09e+04 2.99e+03 -1.0 1.86e+04 - 3.04e-01 6.48e-01f 1\n", + " 146r 0.0000000e+00 1.30e+04 1.58e+03 -1.0 1.46e+05 - 2.04e-01 3.61e-01f 1\n", + " 147r 0.0000000e+00 1.36e+04 3.08e+02 -1.0 1.18e+04 - 9.12e-01 1.00e+00f 1\n", + " 148r 0.0000000e+00 1.10e+04 2.16e+00 -1.0 4.09e+00 -4.0 1.00e+00 1.00e+00h 1\n", + " 149r 0.0000000e+00 1.22e+04 1.65e+00 -1.7 2.94e+01 -4.5 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 150r 0.0000000e+00 1.31e+04 1.64e+00 -1.7 5.03e+01 -5.0 1.00e+00 1.00e+00f 1\n", + " 151r 0.0000000e+00 1.29e+04 3.23e+00 -1.7 3.50e+01 -5.4 1.00e+00 1.00e+00h 1\n", + " 152r 0.0000000e+00 1.19e+04 5.44e+02 -1.7 3.69e+04 - 1.00e+00 6.74e-01f 1\n", + " 153r 0.0000000e+00 3.43e+03 2.19e+01 -1.7 1.23e+04 - 1.00e+00 1.00e+00h 1\n", + " 154r 0.0000000e+00 2.96e+03 5.24e-01 -1.7 1.78e+03 - 1.00e+00 1.00e+00h 1\n", + " 155r 0.0000000e+00 2.99e+03 2.57e+01 -2.5 1.05e+04 - 8.24e-01 8.54e-01f 1\n", + " 156r 0.0000000e+00 4.83e+03 2.10e+01 -2.5 3.56e+03 - 1.00e+00 9.28e-01h 1\n", + " 157r 0.0000000e+00 1.91e+02 6.11e+00 -2.5 7.38e+02 - 1.00e+00 1.00e+00h 1\n", + " 158r 0.0000000e+00 6.34e+01 3.88e-02 -2.5 7.32e+01 - 1.00e+00 1.00e+00h 1\n", + " 159r 0.0000000e+00 1.16e+04 1.91e+02 -3.8 5.52e+03 - 7.33e-01 9.36e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 160r 0.0000000e+00 8.60e+03 5.01e+02 -3.8 4.56e+03 - 3.35e-01 3.58e-01h 1\n", + " 161r 0.0000000e+00 4.61e+03 2.92e+03 -3.8 2.07e+03 - 8.26e-01 5.26e-01h 1\n", + " 162r 0.0000000e+00 3.60e+02 8.99e+03 -3.8 8.68e+02 - 5.05e-01 1.00e+00h 1\n", + " 163r 0.0000000e+00 1.13e+02 3.07e+02 -3.8 5.08e+02 - 1.00e+00 1.00e+00h 1\n", + " 164r 0.0000000e+00 1.67e+02 3.30e+01 -3.8 6.12e+02 - 1.00e+00 1.00e+00h 1\n", + " 165r 0.0000000e+00 1.22e+01 1.46e-01 -3.8 1.59e+02 - 1.00e+00 1.00e+00h 1\n", + " 166r 0.0000000e+00 2.15e+00 1.25e-03 -3.8 1.80e+01 - 1.00e+00 1.00e+00h 1\n", + " 167r 0.0000000e+00 6.62e+02 3.07e+02 -5.7 2.03e+03 - 9.26e-01 5.74e-01f 1\n", + " 168r 0.0000000e+00 4.94e+02 1.08e+02 -5.7 1.15e+03 - 1.00e+00 7.82e-01h 1\n", + " 169r 0.0000000e+00 4.16e+02 2.06e+02 -5.7 6.08e+02 - 9.82e-01 1.68e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 170r 0.0000000e+00 3.63e+02 1.05e+04 -5.7 1.90e+02 - 1.00e+00 9.40e-01h 1\n", + " 171r 0.0000000e+00 4.94e+03 1.45e+05 -5.7 6.81e+00 - 1.00e+00 9.80e-02h 1\n", + " 172r 0.0000000e+00 5.01e+03 1.47e+05 -5.7 3.34e-01 - 1.00e+00 1.00e+00f 1\n", + " 173r 0.0000000e+00 3.29e+03 2.38e+05 -5.7 4.37e-01 - 1.00e+00 1.00e+00H 1\n", + " 174r 0.0000000e+00 1.30e+03 9.35e+04 -5.7 5.77e-01 - 1.00e+00 2.87e-01h 2\n", + " 175r 0.0000000e+00 2.20e+02 1.60e+04 -5.7 9.32e-02 - 1.00e+00 1.00e+00h 1\n", + " 176r 0.0000000e+00 2.98e+01 2.17e+03 -5.7 3.88e-02 - 9.67e-01 1.00e+00h 1\n", + " 177 0.0000000e+00 2.58e+01 8.80e+06 -1.0 4.77e-01 - 9.90e-01 1.00e+00f 1\n", + " 178 0.0000000e+00 5.64e+00 1.91e+06 -1.0 9.74e-02 - 9.90e-01 1.00e+00h 1\n", + " 179 0.0000000e+00 2.20e-04 3.75e+03 -1.0 5.06e-06 - 9.92e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 180 0.0000000e+00 7.45e-09 1.06e-02 -2.5 1.31e-07 - 1.00e+00 1.00e+00h 1\n", + " 181 0.0000000e+00 2.24e-08 2.57e-04 -7.0 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 182 0.0000000e+00 2.24e-08 3.90e-11 -7.0 9.85e-08 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 182\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 3.8958489431350689e-11 3.8958489431350689e-11\n", + "Constraint violation....: 2.9103830456733704e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593320084580268e-14 2.8593320084580268e-14\n", + "Complementarity.........: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "Overall NLP error.......: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 253\n", + "Number of objective gradient evaluations = 22\n", + "Number of equality constraint evaluations = 253\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 185\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 182\n", + "Total seconds in IPOPT = 0.150\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], "source": [ "# Check physical units consistency, solve and check solver status\n", "from pyomo.environ import TerminationCondition\n", @@ -342,11 +1064,886 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Solving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Adding distillation column and resolving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 17\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Complete.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n" + ] + } + ], "source": [ "from pyomo.common.log import LoggingIntercept\n", "import logging\n", @@ -371,7 +1968,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -394,9 +1991,88 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Equipmentfs.H101fs.R101fs.F101fs.F102fs.D101fs.H102
Distillation13.28333413.5522947.7813320.0000007.607433.32944
Two Flash13.28333410.7558787.7813327.7813320.000000.00000
\n", + "
" + ], + "text/plain": [ + "Equipment fs.H101 fs.R101 fs.F101 fs.F102 fs.D101 fs.H102\n", + "Distillation 13.283334 13.552294 7.781332 0.000000 7.60743 3.32944\n", + "Two Flash 13.283334 10.755878 7.781332 7.781332 0.00000 0.00000" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# Compare equipment purchase costs (actual capital costs)\n", "\n", @@ -430,9 +2106,76 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Utilitiescoolingheating
Distillation60.192008367.404722
Two Flash47.028803372.093536
\n", + "
" + ], + "text/plain": [ + "Utilities cooling heating\n", + "Distillation 60.192008 367.404722\n", + "Two Flash 47.028803 372.093536" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAHvCAYAAABQTQWGAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAARd5JREFUeJzt3Qd0VFXb6PEnCQkghBpqQKQjTSJFqdJU6guIIEWsKOCLfHhREZD3xYoCUiwUFRBRQBTpRTpIk6b03juhBAKEPnc9+7szdyZ1EkJmcs7/t9ZZM+ecPTM7JzOTJ3s/e+8AEXEIAACAhQX6ugIAAAD3GwEPAACwPAIeAABgeQQ8AADA8gh4AACA5RHwAAAAyyPgAQAAlkfAAwAALI+ABwDiMWbMGHnllVe4NoBFZPB1BQCIdOrUSZo0aSJvvPGGXLx4Mc4l+fjjjyVbtmzSo0ePOI9RDodDYmJizGN37NghixYtkuPHjyd6aT/55BMpVqyYfPPNN7Jq1apk/xoKFiworVu3lnLlyklISIgcPXpU5s2bJ+vXr083v9Lx48fLihUr5Icffohz7plnnpG7d+/KuHHjxJdy5colLVu2lIiICAkNDZVTp07Jvn375Pfff5eoqKg0vy5AekULD+AHHn30UWnXrp088MAD8Z5/+umnpXnz5vE+ZuXKlTJz5kxZvny5nD17Vtq2bSuHDh2SCRMmSPbs2eN9vqJFi8p7770nzz77rPTq1SvZ9e3Zs6fs37/f1Gnbtm2mDnny5DF/JH/77TfJkiWLpAf681euXDnec6+99pp8//334kvdunWTI0eOmLocO3ZMlixZIpcuXTKB74kTJ+Rf//pXml8XID3TtbTYuAa8B3z4Hhg2bJhDhYeHx3t+w4YNjkOHDnn9mPr16zuuXbvmWLFihSMgICDO+Y8//thx+fJlR//+/R03b9505M+f3+u6du3a1bzue++9F+dc5cqVHdHR0Y558+ali/eT1vWrr77yeT3i215//XVznfV3FPuc/k71+r/xxhu2uy5sXANJ+TXg4nENeA9YLeDRrV+/fuZ827ZtPY4HBQU5jh8/7vjmm28c2bNnd1y9ejXe4CW+LVu2bI6oqCjHmjVrEiyjz6VatGjhOvbTTz85OnToYB7/7rvvOsaPH+/44IMPHIUKFYr3OfLmzevo1auXY+zYsY5vv/3W8eKLLzqCg4M9yjifM2vWrI6ePXua52zatKk5N2jQIMfkyZPNNnHiRMeQIUMcTz75pOux+hg9p8Henj17XGX79u3rKjNmzBjHK6+8Eu9rZsmSxfHWW2+Z19TgsXDhwvH+HDVr1nSMGDHC8d133zk6depkApWBAwc6evfuneR1vnjxomP16tVJlnPff/jhh811/eGHH8zrOq+H+5YrVy5zvUaNGuX4+uuvHZ07d3ZkypTJ6+uS2OPZuAbix9eALi3Aon7++Wdz26JFC4/jTZs2lfDwcBk1apTpHpkyZYq8+uqrXj1n48aNTTfZxIkTEyzz448/mtvnnnvOdUzv16pVS2bNmiXBwcGyceNG81zaHaa5Ke6efPJJk6Oi3TV///237N69W/r372/yjNy7ypzPOXv2bJPbsmvXLilcuLA5p10/M2bMMJve1xwj7fYbOHCgOX/jxg1z7s6dO6b7z1l29erVHjk8VatW9aibvmaNGjVc3Xaar6TXd9OmTZI7d26PstrtpHUOCwsz5apUqWKueaNGjaRu3bpJXuccOXIkep3V5cuXXfdfeukl2bp1q1SqVEnWrFkj169fN/WcNm2aBAb+71d9oUKFZOfOneZn07JbtmwxXaP//POPV9clqccD/s7nURcb18Du7wFna82MGTNc/1W7b+fPn092C49u169fN61D7sdmzZrlWLlypWv/0UcfNc9Tr169JOv54YcfmrK1a9dOtNyFCxccW7dude3funXLdKGVLVvWdSxjxoyOnTt3OrZs2eLReqAtG3od3J8vT5485ri23Lg/p3a9lCtXznUssZYGbYm4ffu2R6tSYl03kZGRphXD/Zi+prZwlSpVynVMr7+2iAwYMMB1rEiRIuaYtoC4P75bt26mRW3+/PmJXr+PPvrIXOdatWp59f7RFib9XU+aNMnjeKtWrczzdO/e3ey//fbbpl6xr1PBggU99hO6Lt4+no1rIH54DWjhAfzIH3/84fqv2n2Lb+SWN3TklnsitI6s0taDkSNHuo5t3rzZtEBoYmxSsmbNam6vXbuWaLmrV6/GSVxeu3ataR1w0tYEHfpdsWJFKVu2rDnWpk0b07IxaNAgj8dGRkaaFho97+6vv/4yo9KctFVDBQUFmbLDhg0zrSSTJ082ibh6vHz58nIvtNVm7969rn1NHtbWJW1ZcWrVqpVpyfr66689HqtJ0AEBAUm+hvPa6e/PG9rikjFjRhk6dKjH8enTp8uBAwekQ4cOZv/mzZumXs7RfU4nT5706nXu9fGALzEsHfAj2uWjf0Bje/vtt03XSHJkyJDBdPVcuHDBdUznldHjGgy4d3VpUKR/pHUItHv52M6dO2duY3ffuNM/6Po827dv9ziuo7pi064rpcPjNRgqU6aMaxSYjlDS53IGCBpQOLusEntO7b7S0WI6Em3s2LGmS0sDB93X0W4JjVzzlgYQsWlAVqBAAde+vpY6ePCgR7lbt24lOV2At9fZnfP13AMxJz3m7DbUIfY6xF27ufR9piP7Fi9eLL/88otXwdW9Ph7wJQIewKJ0WLG2aGi+jHvAo60M+kfKnbYiDR482MztM2LEiASfc926deZW81gWLlwYbxkNTDSAcpZ1ypw5c5yyzmPacuAMCNSCBQtMK1HsYDC26OjoOMc0z+bxxx+XOnXqyJ9//umRu5QanHV1p/MgOfNk3MtkypQpTvn4rkNs2hqm9OdI6Dq7c143fT33vB6lvwtnHa5cuSL169c3rVx6q9dIW/sGDBhgXuv06dOJvs69Ph7wNZ/3q7FxDez+Hrgfo7Q09+fOnTuOSpUqmX0dpaTcc17cN81X2b59e6L11FFGu3btMqO8dERPfGV0VJTmyri/jua+uOfqODcdsaR1zJcvn9l/9tlnTR2ffvrpJK+ZPufgwYPjHNcRRSr2CCYtq5577jnXMc0L0tFqycnhie81Fy1a5JEr9fzzz5vXeuKJJzzK6c+p1yapHB69zjt27HAcPXo0wescEhLiqFixornfsWNH83rNmjXzKKO5NufOnXPMnDkzwdeqU6eOeeybb77p1XXx5vFsXAPxw2tADg9gMdplM3z4cDMp4YcffugaQaM5Otqd4p7z4m7+/Plm1uTq1asn+NzakvHCCy+YPBud6de9y0W7nvr16yfPP/+8GVUV+3U0/8d9NJjm7XTp0kV+/fVXOXPmjCvnREdmaf2d3TROuh87hyc+OnJIuU/UqK0PDRs2jFNWr8eDDz4oqU2vjXb56AzZznwcbQHSlhCdHDIpep31OurvUnOXdFSdu+LFi5uWn9q1a7teT2e6/uijj0x3ovts2jlz5jTXU2k3ZunSpT2eS3N/lHtXZkLXxdvHA/6ILi0gndOlITR/QpNJNY9E8zV0uLfm5GhXldL8Hx3mndgwZ8110UTizp07u7pU4rNhwwapWbOmeV2dBViHLGsSs7MLTYdH6yzPsekfZS2jQY4Oh9fASp+ra9eurjI6HFrzbL777juT06PDvc+fP2+CHc090kAqKXPnzjW5JlqHl19+2eT06LXRmaW1q8ydBgKaOL1s2TLTHaPX7dNPP5V7pddDc100gNM8JU0Mf+ihh0wApD+3/pxJ0cDvscceM3XUvCHtmtQ6avCj11G7JXWGa6W/f00knjp1quzZs8ckoWtelCapv/766+bnU9q1pWX0Wmr+k+Z46dB7vQaa2J3UdfH28YA/Cvh/TT0AfEjzXvQ/Z/1v3jnSKPbcNPqf9Jw5c+I8xtkioMGK/petLSux/9vWP5I6Z40GEPEl+jrpHDH6x8z9dRJTpEgR01KjQYUufaB/pLUu8eWY6B/Rd955xyQm66YtEhoIJET/WD/yyCMmiNI/+Dofj/tza2uPJuQ6W3Ri02tTqlQp06Kio7m0tUR/Pp2jRuvq/jPo62j+i7Y0acKz0oBFy+k1S+o1n3jiCXMNdA0zd/o70+BQ82i0DprcrAGEBivaguMtXbZD66itZPp4/R06E5vdaSubzoujrTMaVOprxs6Fcl6bkiVLmpwcTS6P77kSui7ePh7wRz7vV2PjGvAesPZ7IKHcF7ttOj+P5izpfDa+rgsb10Bsdg3I4QGA+0BHsuXPn99jdJaOgNPurkmTJnHNgTRGDg8A3AfavaSTFGp3UFRUlOlq0mO6mj0T9QFpjxweAPddUvk2VqXJ0hUqVDA5NZrnosnE8c3jA+D+I+ABAACWRw4PAACwPAIeAABgeSQtx5r3I761eQAAgP/SSTCTGgxAwOMW7MS3SjUAAPB/OsFqYkEPAc//42zZ0QtGKw8AAOmndUcbLJL6203AE4teMAIeAACshaRlAABgeQQ8AADA8gh4AACA5RHwAAAAyyPgAQAAlkfAAwAALI+ABwAAWB4BDwAAsDwCHgAAYHkEPAAAwPIIeAAAgOUR8AAAAMsj4AEAAJZHwAMAACwvg68rAN+765jt6yogDQUGNOd6A7AdWngAAIDlEfAAAADLI+ABAACWR8ADAAAsj4AHAABYHgEPAACwPIalA4CFMe2EvTDtRMJo4QEAAJZHwAMAACyPgAcAAFgeAQ8AALA8Ah4AAGB5BDwAAMDyCHgAAIDlEfAAAADLI+ABAACWR8ADAAAsz28CnlatWsmiRYuka9eucc5VrlxZvv/+e5k9e7Z8+umnkitXrhSVAQAA9uQXAU/RokVlxIgRUrZsWSldurTHuerVq8vq1aslOjpaJk6cKDVq1DD7DzzwQLLKAAAA+/J5wJMhQwaZPHmy9OvXT86ePRvnvLbWzJ07V9566y2ZOnWqNGvWTMLDw6Vz587JKgMAAOzL5wGPBiuHDx82LTOxZcqUSWrXri0zZsxwHbty5YosWbJEnnrqKa/LAAAAe8vgyxd/+umnpW3btlKpUqV4zxcuXFiCgoLk+PHjHsd1v169el6XiU9ISIhkzJjRtR8aGnqPPw0AAPBXPmvhyZcvn4wfP15efPFFiYqKSjAoUTExMR7Hr1275jrnTZn49OnTRy5fvuzaTpw4cc8/EwAA8E8+C3hat24tWbJkkffff9+MztKtePHi8swzz5j7AQEBcvHiRVM29oir3Llzu855UyY+AwcOlGzZsrk2zfkBAADW5LMurZkzZ8qePXs8jo0ePVq2bNkio0aNEofDISdPnjSJzI8++qjMmzfPVU73N2zYYO57UyY+N2/eNBsAALA+nwU82oUUuxtJk42PHTtmEo6dJkyYIK+++qqMGTNGIiMjpXHjxhIRESHdu3dPVhkAAGBfPk1a9sZ///tfKVeunOzbt08OHDggDz/8sLzzzjuyZs2aZJUBAAD25VcBT5cuXeLk3WgyctOmTaVkyZIm0XnXrl1y/vz5ZJcBAAD25VcBz/r16xM8p603uiXGmzIAAMB+fD7xIAAAwP1GwAMAACyPgAcAAFgeAQ8AALA8Ah4AAGB5BDwAAMDyCHgAAIDlEfAAAADLI+ABAACWR8ADAAAsj4AHAABYHgEPAACwPAIeAABgeQQ8AADA8gh4AACA5RHwAAAAyyPgAQAAlkfAAwAALI+ABwAAWB4BDwAAsDwCHgAAYHkEPAAAwPIIeAAAgOUR8AAAAMsj4AEAAJZHwAMAACyPgAcAAFgeAQ8AALA8Ah4AAGB5GXxdgYoVK8pTTz0lWbNmlR07dsj06dPl9u3brvPPPvus1KxZ0+Mxp06dkkGDBnkcy5s3r3To0EHy5csn27Ztk19++UXu3LmTZj8HAADwXz5t4Rk8eLCMHj1acuTIYfY//PBD2bBhg4SGhrrKNGjQQOrWrSuHDx92bSdOnPB4nhIlSpggp1GjRnLr1i354IMPZMGCBRIYSAMWAAAQCRARh68uROnSpWXPnj2u/dy5c8uZM2fk+eeflylTpphjo0aNkrCwMGnTpk2CzzNt2jRTRgMjh8MhhQsXlv3798urr74qP/30k1d10SDr8uXLki1bNomOjhY7ueuY7esqIA0FBjTnetsIn297sePnO9TLv98+bQJxD3ZU5syZJSAgQC5evOhxvHjx4vLJJ5/Iu+++K9WrV/c4lyFDBmnSpIlMmjTJBDvq2LFjsnz5cmnZsmUa/BQAAMDf+bzPR1t5hg0bJmPHjpVFixZJv3795I8//nCd1yDmwoULcv36dSlWrJgsWbJEvvzyS9f5Bx98UDJlyiQHDhzweF7dL1myZIKvGxISYqJC9w0AAFiTz5OWY2JiTF6Odklpzo0mKGfJkkWuXr1qzn/22Wdy9OhRV3nt6lq2bJnMnDnTBD8PPPCAOR67GUubt5zn4tOnTx8ZMGDAffu5AACA//B5C48GMyNGjJD+/ftL1apVzdazZ0+P8+60q0qP1apVyyPQcSY+O+XMmTPRvryBAwea/j7nFh4enso/GQAA8Bc+D3hit8rs3r1bypQpk2g57Y4KDg429zX40cAm9mN0f+fOnQk+x82bN83j3DcAAGBNPgt4NGCJPb/OQw89JBEREbJp0yazHxQUJHXq1PEo0759e8mfP78sXLjQleOjo7ReeuklyZgxozlWoUIF89xTp05Ns58HAAD4L58NS9fRVfPmzTMjs7QlRrukGjduLPPnz5dOnTqZFhjN6dEymlCskxJqgrIGQDpiSzcnnWxwxYoV5jF///23GbU1d+5cEwR5i2HpsAs7Dlu1M4al24sdP9+hXg5L9+k8PEpbdHTTJOV//vknzlB19zI6XH39+vVxJh5UOlJLAybnTMurV69OVj0IeGAXdvxCtDMCHnux4+c7NL0EPP6CgAd2YccvRDsj4LEXO36+Q9PDxIMAAABpgYAHAABYHgEPAACwPAIeAABgeQQ8AADA8gh4AACA5RHwAAAAyyPgAQAAlkfAAwAALI+ABwAAWB4BDwAAsDwCHgAAYHkEPAAAwPIIeAAAgOUR8AAAAMsj4AEAAJZHwAMAACyPgAcAAFgeAQ8AALA8Ah4AAGB5BDwAAMDyCHgAAIDlEfAAAADLI+ABAACWR8ADAAAsj4AHAABYHgEPAACwPAIeAABgeQQ8AADA8jL4ugI5c+aUmjVrStasWWXHjh2ybdu2OGWCg4OlQYMGki9fPnN+8+bNKSoDAADsyactPD169JANGzbISy+9JC1btpSVK1fKtGnTJEOG/x+HhYWFyaZNm2T48OHStGlTWbx4sYwaNcrjebwpAwAA7MunLTy7du2Shx9+WG7dumX2S5QoIfv27ZPmzZvL9OnTzbGBAwea24iICImJiZFHH33UBEmzZ8+WefPmeV0GAADYl09beBYtWuQKdtTZs2fl9u3bEhQUZPYDAgKkbdu2Mn78eBPIKO2qWrNmjbRr187rMgAAwN58nsNTqFAh0w2VLVs2adOmjfz888+u1p3ChQub4zt37vR4jO5XqVLF6zLxCQkJkYwZM7r2Q0NDU/knAwAA/sLno7Q00KhUqZJUq1ZNwsPDJTIy0nVOAxkVFRXl8ZiLFy+6znlTJj59+vSRy5cvu7YTJ06k6s8FAAD8h89beDSPp1u3buZ+kSJFZMuWLXL48GH55ptvXF1UsVtfNJC5du2aue9Nmfho3s/QoUNd+/p4gh4AAKzJ5y087o4cOSJ///23PPbYY679GzduSNGiRT3K6f7+/fu9LhOfmzdvSnR0tMcGAACsyWcBjyYma/6Nuxw5cki5cuXkwIEDZl8TmBcsWOCRfFygQAGpV6+ezJo1y+syAADA3gJExOGLF9ak4Y0bN8pff/1lEow12OnQoYNpaalfv74rJ6d06dJmxNWqVatk3bp18sILL5jRXFrmzp07XpdJinZpaS6PdoXZrbXnrmO2r6uANBQY0JzrbSN8vu3Fjp/vUC//fvushUe7lCpXrixLly41LTJ3796VXr16mWPuCch79uyRihUrmkBGZ1EeMmSINGzY0COQ8aYMAACwL5+18PgbWnhgF3b8D9DOaOGxFzt+vkP9vYUHAAAgrRDwAAAAyyPgAQAAlkfAAwAALI+ABwAAWB4BDwAAsDwCHgAAYHkEPAAAwPIIeAAAgOUR8AAAAMsj4AEAAJZHwAMAACyPgAcAAFgeAQ8AALC8FAU8DRo0SP2aAAAA+FPAs2DBgtSvCQAAgD8FPIcOHZLSpUunfm0AAAD8JeD59NNPZcKECVKzZk3JmTOnZMmSxWMDAADwJxlS8qDx48eb21WrVsV7PiAg4N5qBQAA4OuA5/HHH0/NOgAAAPhfwPPXX3+lfk0AAADuE+bhAQAAlpeiFh71/PPPS5s2beTBBx+UDBk8n6ZChQqpUTcAAADftfC8/fbbMmjQINm8ebNUqlRJfvrpJ9m7d6+ULVtWli9fnjo1AwAA8GXA8/rrr5vWnQ8++MDsf/7559K6dWvp2bOnFC1aNLXqBgAA4LuAR4MaZ+JyTEyMZM2a1dzXuXnq1KmTOjUDAABIJSkKeDRn5/bt2+b+0aNHpWrVqua+5vPcunUrteoGAADg26Rlp3Hjxskvv/wiS5YsMa07v//+e+rUDAAAwJcBT1hYmOu+Ji+fPn1aqlevbu6PHDkyteoGAADgu4Dn/PnzHvs//vij2VJUgQwZpEyZMqaL7MCBA3G6xEqWLCkFCxb0OHb16lXZuHFjnOd66KGHJF++fLJnzx6JiopKUX0AAID1pLhLKzg42LTqFCtWTH744QdzLG/evHL27Fmvn+M///mPvPHGG3LmzBl54IEHzNatWzeZNWuWq8z/+T//x4wA27Fjh8dq7a+88oprP1OmTDJlyhRp0KCBOVeiRAnp27evDB8+PKU/HgAAsHvAo8nJ8+fPlyJFipjV0Z0BzzfffCMTJ070CFgSoguM6la6dGm5dOmSOfb+++/L5MmTpXjx4qabzGnFihVmGHxCBgwYIBEREeZxGnA1a9ZMZs+eLWvXrmUZDAAAkLJRWtpyokFI9uzZPY4PGTJE3nvvPa+ew+FwmHl8nMGO+vbbb00rjwYv7jJnzmxGgpUqVUqCgoLiPNdLL70k33//vat1ac6cObJlyxZ5+eWX+RUDAICUtfDoaCwNPu7cueNxfPv27XGCleSoVq2aud2/f7/H8YYNG0qBAgUkf/78JlDq2rWrCWqU5vdo3s6mTZs8HqP7idUlJCREMmbM6NoPDQ1Ncb0BAIAFW3g0WHC6e/eu6354eLhJKE6JPHnyyNdffy2TJk2Sffv2uY7PmzfPBDWVK1eWQoUKmckNdRi85umonDlzmtsLFy54PN+5c+dc5+LTp08fuXz5sms7ceJEiuoNAAAsGvDoelmabKy0xUVpLs8XX3whixcvTvbz5ciRQxYsWCDHjx+X1157zeOc5uI4gxl9rf79+8uNGzekefPm5tjNmzdd3V7utGvMeS4+AwcOlGzZsrk2DdYAAIA1pahLq1evXrJy5Upp2rSpSTzWyQZr1qxphpbrbXJoHtDChQvl+vXr0qhRI7l27Vqi5bVFSQMg51B1DZK0ay12wKL7R44cSfB5NBhKLCACAAA2b+HRLqfy5cvLzJkzZfr06ebYV199JY888ogcPnzY6+fRlhUNdjRQ0mDnypUrccpoS407zR3S+Xa2bdvmWstr9erV8q9//ctVRlubNO9n0aJFKfnxAACAxQRoT1FyH6TJwH///fc9vbBOOKitRDqPj3ZjaR6Nk04cqMPSda6ff/75xwx713l4dDi8jgI7efKkPPHEE65JCmvVqmWWthgxYoQZit69e3cpXLiwqae3OUWatKx10CAsOjpa7OSuY7avq4A0FBjwv93BsAc+3/Zix893qJd/v1MU8GgujQYiuo7WTz/9JBcvXkx2BbVi2kIUn8GDB5tkZedkhv/+979N8KKv8+eff8r48ePjjBB77LHHTF6RjtjS1h9d5iIyMtLr+hDwwC7s+IVoZwQ89mLHz3fo/Qx4dISUznT8wgsvSO7cuU3gosGPdiE5k5jTGwIe2IUdvxDtjIDHXuz4+Q71MuBJUQ6PzpOjSzdoF5Mu+6DdUzqaSvN3PvzwQylatOi91B0AACBVpSjgcR8xpV1PnTp1Mrk12p2kw8Y1INKRWzpvDgAAQLoOeDRvZsyYMXLq1CmzyKfm3mjrzuOPP24SjmfMmJF6NQUAAEjreXg0h6dkyZKmhef55583t85Zl7VrSxf7jG+YOQAAQLoIeHQtK01S1tFS7quau9OJBF999dV7rR8AAEDaBjw6RFxXJNeWHW/oulcAAADpKodHl3FYt26dvP/++1KpUqX7VysAAABfBTy6ftXIkSOlYsWKZgHRY8eOyejRo6VZs2ZxFu8EAABIlwHPuXPn5Mcff5S2bdtKWFiYvPjii2axT10l/fz58zJnzhyT38NwdAAAYIlh6brg59KlS81w9NKlS5uFQ3Vfg6EDBw6YpScAAADS7SithFZQHzp0qNl0emdd/RwAACDdBjylSpWSGjVqmJmVAwICzND0NWvWyN69e815XdNi6tSpqV1XAACA+x/wZM+eXSZOnCjNmzc3kwxeunTJLBaaI0cOCQwMNOtp6SSEGvAAAACkyxyeL7/8UooUKSJPPfWUZMyYUXLlymVWS9f7Tz/9tDmnZQAAANJtC0+LFi2kSpUqZnHQ2AnMCxculEOHDsn69etTu44AAABp18Kj3Va3bt1K8PzNmzclKCjo3moEAADgy4BHFwj9+eef5dFHH41zLiIiwpzTMgAAAOk24HnzzTdNsvKmTZtMwrJ2bemm9zdv3mzOde/e/f7VFgAA4H7n8ERGRkqdOnXkscceM8PS8+fPb447h6X/9ddfKakDAACA/83Do4ENwQ0AALD1xIMAAAD+hIkHAQCA5THxIAAAsDwmHgQAAJbHxIMAAMDymHgQAABYHhMPAgAAy2PiQQAAYHlMPAgAACzPLyYezJgxo9y5c0du376dYBldhT1r1qxm3a57KQMAAOwnWTk82bNnl1mzZsmePXtk7Nix0rt3b3nnnXfMfT2m57Jly+b187Vt21bWr18v586dk8uXL8uqVaviXYn9s88+M0HMqVOn5MiRI9K8efMUlQEAAPbks4kHAwMDpVWrVtK1a1cTSOlz7d69W+bPny85cuRwlXvrrbfk9ddflyeeeMK03gwfPlx+++0308qUnDIAAMC+AkTE4W3hqKgoqVKliuzfvz/e8yVLljQtNjlz5kxRZQoWLCgnTpwwwdPChQvNsYMHD5rg5d1333WVO3DggMyYMUN69erldZmkhIaGmlYmbaGKjo4WO7nrmO3rKiANBQbQ+mknfL7txY6f71Av/3771cSDRYsWNbdnzpwxt2FhYeaYdnW5+/PPP6VatWpelwEAAPbmNxMPZsqUyXSHLV++XLZs2WKO5cmTx9xqjo+7yMhIyZs3r9dl4hMSEmKiQvcNAABYk19MPJghQwaZOnWqyeVp376967jD4XCdj11eR3V5WyY+ffr0MU1gzk270gAAgDX5fOJBZ7BTrlw5k3Ssz+V08uRJc6vD393pvvOcN2XiM3DgQBk6dKhrX1t4CHoAALAmn048qPk+U6ZMkUceeUTq1q0rx48f9zivLS///POPPPnkk/Lrr7+6HtOgQQP55ptvvC6TUL6RbgAAwPpSFPAkRoem6zw4SdEJCydNmiS1atUyc+Zo8OFspdEusuvXr5v7H3/8sSm3bt06Wbt2rbz99tsmeXrUqFGu5/KmDAAAsK9k5fB44/Dhw16V07l2tHtMc3B0wkJtpXFuOj+P07Rp0+Tll1+WLl26mDl6NBFZW4O0ey05ZQAAgH0lax4eb2gAo6036Q3z8MAu7DhPh50xD4+92PHzHerlPDzJ6tI6dOhQatQNAAAgTSUr4NFlJEaOHJloBKX5NAAAAOk24NHEYM3RGT16dIJlCHgAAEC6TlrWUU8dO3ZMtIzOlAwAAJBuAx5d8qF27dqJlqlXr9691gkAAMC/h6UDAABYMuDRIWG6MrkOCQMAAEj3AY/OpPzRRx+59kuUKCH79u0zS03osPUqVaqkdh0BAADSNuAZNGiQ7Ny502PV8YULF5pWHh2yzigtAACQbgMeXclct8aNG0tMTIxrXxft1PWrKleuLBs3bjRdW85zAAAA6WoenkqVKpnb4OBgKVOmjAl6wsLCJFeuXBISEmLO623mzJldZVesWHH/ag4AAJDaAc+IESPMbbt27eTq1avy1VdfyX//+19ZuXKl61yFChXkueeec+0DAACku5mWVf/+/WXmzJkyZMgQuXXrljRs2NB1TlcsHzduXGrXEQAAIG0DnsWLF5uRWRUrVpRt27bJyZMnXeeWLFliEpgBAADSdcCjTp06ZbbY5s6dmxp1AgAASFXMtAwAACyPgAcAAFgeAQ8AALA8Ah4AAGB5BDwAAMDyCHgAAIDlEfAAAADLI+ABAACWR8ADAAAsj4AHAABYHgEPAACwPAIeAABgeQQ8AADA8gh4AACA5RHwAAAAy/NpwBMSEiIdO3aUP//8UyIjI6VGjRpxygwePNicc99WrlwZp1ynTp1k48aNcuzYMZk3b55UqFAhjX4KAADg73wa8Hz00UfSuHFj+eqrryQsLEyCg4PjlMmaNausWbNGypQp49qaN2/uUaZNmzby/fffm+dp0KCBHD9+XJYtWyZ58+ZNw58GAAD4qwy+fPHevXub2/Dw8ETL3bx5U86fP5/g+X79+sn48eNlwoQJZr9r167yr3/9S9544w0ZMGBAKtcaAACkN+kih6devXpy5MgR2bp1q3zzzTemNcgpW7Zs8sgjj8jixYtdx+7evStLly6V2rVr+6jGAADAn/h9wHPq1Cl5++23pW7duqbFJiIiQlavXi2ZM2c25wsWLGhuz5w54/E43S9QoECi+UOhoaEeGwAAsCafdml548MPP3TdP3TokLRo0cIkJrdr1850YwUEBJhzd+7c8Xjc7du3JTAw4XiuT58+dHcBAGATft/CE5uO0jp69KhJXnbuqzx58niU033nufgMHDjQdIc5t6TyiAAAQPqV7gIe7crSbixnMHPu3Dk5ePCg1KpVy6NcnTp15K+//ko0ETo6OtpjAwAA1uTXAY/m2Xz77bdStGhRs6/Jyj/88IPprpo8ebKr3JdffimdO3eWatWqSVBQkLzzzjsmKBozZowPaw8AAPyFTwOe5557zrTU6OgrNXPmTLOvAYuzFWbVqlUyZ84cuXLlihw+fFiyZ89uRl+dOHHC9TwjRoyQkSNHmpFa165dk27duskzzzwj+/bt89nPBgAA/Idm/Dp89eLOkVKxadASExPjcSxjxoxy48aNRJ9PE5izZMligqPk0npcvnzZ5PPYrXvrrmO2r6uANBQY4DlxJ6yNz7e92PHzHerl32+fjtJKakJBd0kFO8rhcKQo2AEAANbm1zk8AAAAqYGABwAAWB4BDwAAsDwCHgAAYHkEPAAAwPIIeAAAgOUR8AAAAMsj4AEAAJZHwAMAACyPgAcAAFgeAQ8AALA8Ah4AAGB5BDwAAMDyCHgAAIDlEfAAAADLI+ABAACWR8ADAAAsj4AHAABYHgEPAACwPAIeAABgeQQ8AADA8gh4AACA5RHwAAAAyyPgAQAAlkfAAwAALI+ABwAAWB4BDwAAsDwCHgAAYHkEPAAAwPJ8HvBUrlxZvvvuO/nzzz+lUqVK8ZapXr26/PTTT7Jo0SIZOnSo5M2bN0VlAACAPfk04Pnggw9k9OjRcvDgQalVq5Zkz549TpnatWvL8uXL5dixY/LVV19J+fLlZfXq1ZIlS5ZklQEAAPYVICIOX714jhw5JCoqSsLDw+X48eNSt25dWbFihUeZlStXyqlTp+S5554z+w888IDZHzBggAwbNszrMkkJDQ2Vy5cvS7Zs2SQ6Olrs5K5jtq+rgDQUGNCc620jfL7txY6f71Av/377tIVHg53EZM6cWWrUqCGzZs1yHbt27ZosXrxYnnzySa/LAAAAe/N5Dk9iChcuLEFBQXLixAmP47r/4IMPel0mPiEhISYqdN8AAIA1+XXAExwcbG6vX7/ucTwmJsYELN6WiU+fPn1ME5hzix0wAQAA6/DrgOfChQvmNnfu3B7Hdd95zpsy8Rk4cKDp73NumkcEAACsya8DHk08Pn36tBm67q5atWry999/e10mPjdv3jTJTe4bAACwJr8OeNT48eOlc+fOkj9/frPfokULqVChgjmenDIAAMC+MvjyxRs1aiT9+vVz5droHDqXLl2ScePGuYIVnaundOnSsn//fjly5Ig89NBD0qNHD1m/fr3rebwpAwAA7Mun8/DkyZNHSpUqFef40aNHzSSC7nQ0Vr58+WTv3r0myTg+3pRJCPPwwC7sOE+HnTEPj73Y8fMd6uU8PD5t4YmMjDSbNzQAih0EpaQMAO9lyJBBChQoIIGBft/7bQsOh0POnTtn5hoDkDw+DXgA+C9dj+7jjz+WTJky+boqiEWX0tFufw2AAHiHgAdAHAEBAWYgwJUrV2TIkCFy48YNrpKftLiVKVNG2rZta/Y13xGAdwh4AMS7zp3+YR05cqTJiYP/OHDggLnVtQOnTJlC9xbgJTrmAcThXGrl7NmzXB0/tHv3bnMbFhbm66oA6QYBD4B4u7TUnTt3uDp+6Pbt2x6/JwBJI+ABkG7pH/wiRYq41tRLat+b5wBgTQQ8AHyeiKsBR3yL/eq8Ws518nRovJbT8k65cuWSw4cPS9myZb3a9+Y5AFgTAQ8An9JZ0jXgiIiIiHNOk3KHDx/umqhUy2l5J+1y02O6Nl58Yp9PyXMAsAZGaQFIF3QmdVWwYEEzXP769esmqbpu3bpy8uTJeB+jS9W4n0/uc+jMrdrlpc8TH22Vypo1q1y4cCEVf1IA9wMtPAD8nnZF/f777+a+TrinE+/p2ntJdUe5n0/Oc5QrV07WrFljgqBDhw7Jrl27pE6dOq7zOhnj1KlTTSC0c+dO8/iWLVve9+sAIOUIeAD4vbt370rVqlXN/aefflqKFi3qmnwvtZ8je/bssmjRIhMcaQuPBkQ6+eKMGTPM7NOqa9euUqFCBdNSlD9/fqlevbqUL18+VX5WAPcHAQ8AuOnYsaPExMTI5MmTTUCj3WALFy40ixM++eSTpowGQefPn5eoqCizf+rUKbMMBwD/RQ4PALjRlhpttVm1apXHddF1q7T1R33//ffSrl072b9/v8ybN8+0CM2ZM8e0IgHwTwQ8AHzKmfCry1nEljNnTtm6dWua1kdHbWlejrP7Kz5Hjx41S29oV1b9+vXliy++kN69e5s8HyZrBPwTXVoAfEq7gzToqVatmsdxDYBKlCghO3bsMPvOBUzd59BJLm+eQ5OVK1asKMWKFYtzThOfnbfamrN69Wr56KOPpGnTplKjRg0pVapUiusG4P6ihQeAzw0YMMAEDqdPnzZBhE422K9fP7P/448/mjKaL6NDyFu1amXyaa5du+ZaYsFb3jzHr7/+Kt27dzddVNpqo4t16rw9eqxHjx4mABs6dKgZ1q7dWfqcr732mkRGRprRWgD8Ey08AHxOh4e/9NJL0rx5czPc+9NPP5Xt27ebbiWdK8fpxRdfNHPmaBKxPib2pIFJ7XvzHBoANWzY0Ex6+P7775v6tG/f3gRlztamPn36mIDn888/N+V0QsN69eqZZGcA/klXnnP4uhL+sjq0/senw1Cjo6PFTu46Zvu6CkhDgQHNkyyjyy9oi0v//v3lyJEjaVIveC85vx8+3/bizefbrn+/aeEBAACWR8ADAAAsj4AHAABYHgEPAACwPAIeAABgeQQ8AADA8gh4AACA5RHwAAAAy2NpCciw7WFcBQCApdHCAwDJpEtf6LISCe0D8D+08ADw2hfb1qbp1epVobr4owIFCnisuB57H4D/8ftPaMeOHc1Cf+5OnDhhFvJzV7hwYbMoYL58+WTbtm3yww8/eCwYCAD3iy4mCsC/+X3AU6tWLalUqZKMHj3adezChQseZR5++GFZvXq1LF++XNatWyc9evSQF154wQRKuvIxAPvQz/2bb74pxYoVk127dpl/jvbu3es6ryufv/LKK2aF8927d8vHH39sVmZ3500Zd/qdExQUJL179zb7w4cPN4sZRkVFSZMmTSRTpkzy+++/y7Bhw8Th+P/rNWs9O3ToYFaEX7RokYSEhEiOHDmkZ8+e9+XaAHaWLnJ4Dh8+LGPHjnVt06dP9zivfeebN2+WZ555RgYNGiQNGzaUypUrS6dOnXxWZwBpr02bNjJ//nzZsmWLvP766zJjxgwZMWKE67y2An/33Xfy66+/mvOXLl2SNWvWSHh4eLLKxKZdWgULFnTta9n33ntPihYtalp/vvzySxN46T9iTt27dzeBlP4zp2X1H7e+ffsm+joALNzCo0qXLm2+tPSL588//zT/CTkFBwfL008/Lf/+979dx06fPi3Lli2T5s2by/jx431UawBpbciQIea74sMPPzT7GzZskGnTprnOa4Dx2Wefybfffmv2169fL9WqVTMtM9pK420Zb/zzzz+mBcdZD/2eaty4sUyYMMEc00Doo48+cu1v3LhRateunWrXAkA6a+HR5t+DBw+aVp4HHnjAfHm5BzEPPvigaQbW8+4OHTokJUqUSPB59TGhoaEeG4D0S/P49Ptg7ty5Hsfv3LljbsPCwqRQoUKydOlSj/OLFy+WiIgIr8t4S1uZ3J08eVLy5s1r7mtXmbYIrVixwqOe2pIEwKYtPPqfmrbYOGnAs2rVKpkyZYr88ccfkjlzZnM8Ojra43G67zwXH/3vKnbiM4D0K2PGjOb22rVr8Z53fh/ExMR4HNd9/WfK2zLeii9/MCAgwON1NHcn9utoqzUAG7bwuAc7au3atXLs2DGpUaOG2dfEQJUzZ06Pcrly5XKdi8/AgQMlW7Zsro1+cyB9O3r0qAl2Hn300XjPHz9+3AQUFSpU8DhesWJF2bdvn9dlUoO+zo0bN6Rs2bIex2PvA7BRwBMf/e/I+Z+SBj+a2xP7i6JcuXKJjqrQIevaCuS+AUi/9DM9ZswY6d+/v5QvX94cy5Ili0kIdnaPa16Otu5qkrHSvJqmTZvKqFGjvC6TGu7evWumztDXyZ07tyvh+vHHH0+11wCQjrq0dJinftnMmzfPdaxz586mH1xHYji/oH755RczhFRHO+h/eFWqVDFfHJoQCMA+NLFYJwDUJGGdvkK7ud5//33X+X79+plARnP89LwGRO+8845HLo03ZVKDBju//fabye05f/68mV9MB2TcunUrVV+HpWOAdBDwaDDz6quvmmnbd+7caRISH3nkETNHhXZtOelQziVLlpgkwa1bt0qDBg3Mf2MLFizwaf0Bq/HXmY+dNFjQkVTvvvuumYRUW4C1NcXp6tWr8txzz5lubG1Z0a6l2AGGN2ViTzQYe1/r4EyWdtK5eZwjv9TFixfNd1X+/PlNLo/O2aPfYxr4ALBZwKNfVK1bt5ZSpUqZyQf1C0Ln29H/htzpvrbq1KtXz3zJaaJz7BESAOxDA4gjR44keF7z+xLL8UuqTOzcwtj7p06divMY/Z5y/+7SbvciRYq4WrA1yNJJE91bpADYJOBx0llS3WdKTWhEhPv8PADgz7T1Sef8+fHHHz267N1brwHYLOABAKvR1qNWrVqZ4e7afRa7lQhA6iLgAQAf0oEWCc0dBMDmw9IBAACSg4AHAABYHgEPAACwPAIeAABgeQQ8AADA8gh4AFjGiy++KM8++6zPXr99+/bSsWNHn70+gIQR8ACwjGbNmpnlGtKCBjYa4Lh76qmnpFGjRmny+gCSh3l4AHjtrmN2ml6twIDm4q80sNEZ3idPnuw6NmnSJAkICPBpvQDEj4AHgOVUrFjRtLZkypRJZs+eHWdtvezZs5vWGV3LStfc+vXXXz3WuWratKk0bNjQ3Nc1/DZu3Oha80q1bNlSKleubBY4HjZsmDmmt2FhYRIYGOjRxaaLkerSOInVp2zZstKmTRuzBtjSpUulcOHCEhoaKhMmTLhv1wiwG7q0AFhK48aNZfz48ZI5c2YpVqyY/PXXX/L444+7zpcuXVp27NhhAppLly7JE088ITt37jTHnTTIOXz4sNmCg4Nl5MiRMnbsWNf5CxcumEDmypUrrnI3btyI06WlXWxDhgxJtD76+n///beUKVPGBES6ttbQoUPNYwGkHlp4AFiKdinVrFnTtJao3Llzy+uvvy7r1q0z+99++60JKvr27et6zKhRo+TTTz+V1q1bm/01a9aYzWn06NEmqPn8889Na83KlStl9+7dpktrxIgR91SfwYMHyw8//CBdunQx+xpcHTx4MNWvC2B3BDwALGX58uWu4EJpa07VqlXN/Zw5c0qdOnXk5MmTJtDQYES3okWLysMPP+zxPBqk1KpVS/LmzWu6qbQFR7ueNOBJrfpkzZrV3H/77bdd5yMjI2Xx4sUp/vkBxI+AB4ClxF6I886dO5Ihw/9+1eXJk8fcHjt2TE6cOOEqc/ToUZkxY4ZrX4OhF154QaZMmSLHjx+XmzdvmtYczf1JzfpoMOUMctzpvgZnAFIPAQ8A2zhz5ozcvXtXNm3aJL/88ku8ZTQY6d69u7Ro0UIWLlzoOqZBkDtNWL5X2tKk9QkPD5ddu3a5jus+K6gDqYukZQC2oUnKCxYskPfee890JzlpQrF2dSntvgoKCnK1wqgePXqY5GV3UVFRKWrxcaddXcuWLTM5PU6a2JxWcwkBdkILDwBb6dy5s8yZM8e0qGiujAY+ERERMnDgQJOMrN1XmsQ8ceJEmT59uhQsWNDk92iw5G7+/Pkybdo0GTdunDnnHJ6eXL169TJBz6pVq2Tfvn1St25d2b9/v2n5AZB6CHgAWGIiQKXDv2NiYjyOzZ07V/755x/X/qlTp6RKlSpmOLgOBddurm7dusm5c+dcZf7nf/7HBDOapHz27FnTKtSuXTtZv369R8Cjw8s16ViDJk1qjj3xoDf10Tl5dEi8zv2jLT7/+c9/ZPjw4R7zAgG4dwQ8ACzDfXJAJ+fw79j5Nzp6SreEaGuPbk7akhPb1q1bzea0aNGiZNdHW5C0VUmHpiudDFHn83nttdcSrBuA5CPgAQAf0lwh7VrTlh4dwdWkSRPTCjR16lR+L0AqIuABAB/SIfHaNVa/fn3JkSOH6c7SpSwApC4CHgDwscuXL3vMAwQg9TEsHQAAWB4BDwAAsDwCHgBxOGcRdp98D/4jY8aM5laTnAF4h28zAHHoWk63bt2SVq1amcn3dB0p+J7OAK3rb7Vt29bM2XP69GlfVwlINwh4AMShk+XpzMFvvfWWVKxYkSvkZ3bv3m1mhiYQBbxHwAMgXtu3bzeLaOoK4+6zB8O3XY06okuXskiNxUsBO7FMwKOL/+nU7Pny5ZNt27Z5zJAKIOUtPTpPDACkd5ZIWs6fP7+ZpbRfv35SuXJl+fXXX83CfwAAAJZp4fn8888lOjpaqlevbtakKVeunAmAfvvtN5k5c6avqwcAAHws3bfwBAYGyjPPPCMTJkwwwY7asWOHrFq1yoxkAAAASPctPIULF5asWbPKnj174oxiqFatWoKPCwkJcc1loUJDQz1u7SQkMMjXVUAasuN73M74fNuLHT/foV7+zBms8oNGRUV5HNf9xC5Cnz59ZMCAAXGOnzhx4j7UEvAf3S9f9nUVANwndv58h4aGmvQWywY8165dM7fZsmXzOJ49e3a5evVqgo/TOSyGDh3qcSxXrlxy4cKF+1RT+NsHQ4Pb8PDwRD8gANIfPt/2/J2fPHky0TLpPuA5cuSImXG0ePHismjRItdx3d+3b1+Cj9N8H2fOjxN/+OxHf+f83gFr4vNtH9Fe/OOa7pOWdS2ZuXPnSseOHV2ToxUpUkSeeOIJMyU+AACARgjpfrrOYsWKyZo1a8yEg+vXr5d27dqZ1p0mTZrI3bt3fV09+Gnzp85Yq12htPAA1sLnG5Zs4VEHDx6U8uXLy6xZs8x063379iXYQaJu3Lhhktb1FoC18PmGZVt4AAAALN/CAwAAkBgCHgAAYHkEPAAAwPIIeAAAgOWl+4kHAW+VK1dOXnnlFXnwwQclQwbPt/748ePNKD8A6ROfbySFgAe2ULp0adm4caNs2LBBtm/fbiasdHflyhWf1Q3AveHzDW8Q8MAWWrRoITNmzJD27dv7uioAUhmfb3iDHB7Ygs64vXv3bl9XA8B9wOcb3iDggS0sWbLEzL4dO3cHQPrH5xve4NsftpA/f37JnTu3bN26VRYvXixXr171OK8L0K5atcpn9QOQPI0bN5Y6deq49vl8IykEPLCFQoUKyaFDh8z9hx9+OM75TZs2+aBWAO7lM12lShXXPp9vJIW1tAAAgOWRwwMASPd0fq1cuXKZ+0FBQfLmm2/KZ599JiVKlPB11eAnaOGBbQQGBpqJBxs2bCgFChSQ48ePy+zZs2XKlCm+rhqAexAWFibLli0zOT0XL16Uvn37yltvvSV79+6VokWLSvHixSUmJoZrbHO08MAW9D8+/UIcOnSoGcKqOTshISEybtw4mTZtmq+rB+AetG7d2ny+NdhRnTp1MnNu1axZU3bt2iWNGjXi+oKkZdjnCzE8PNz8pxcZGek6rv/9rVu3zvxnuHLlSp/WEUDKFCxY0PW51tZb/axrAKQ04NFRmgAtPLCFihUryuTJkz2CHefIDu3W0vMA0qc9e/ZIy5YtTWDTo0cPE+w4l48pVaqUOQ8Q8MAWtKlbv/jio8cvXLiQ5nUCkDp+++03k6Nz6tQp6datm3z88cfmeJkyZSRfvnyyfPlyLjVIWoY9FClSxDRtjx07ViZMmCBnz54183i88cYbpn+/ZMmSrv5/AOnTQw89JOfOnXMtBqyf8YCAADl27JivqwY/4WDjGtjhPVCnTh3Htm3bHO7WrVvniIiI8Hnd2LgGvAd4D/AekPt6DRiWDtvRpEbnsHRt6QFgDZrDo91Y2bNn9zi+fft2OXDggM/qBf9BVMk14D3Ae4D3AO+BdP0eGDRokOPWrVtmu3HjhqsV9/r1644333zT5/VjE59fA1p4YFktWrQwkwxOnz5dQkNDzf2EaJmlS5emaf0ApI66devKpEmTzGf85ZdfltOnT8v3338vPXv2lA4dOphRmDdu3OBy2xyLh8KycuTIYZIWs2bN6rqfEC0DIH16/PHHZeLEibJz505xOBwSHBwsly5dkg8++EBq1KhhVlafMWOGr6sJHyPggWXpaCzdnFPPz5o1K96RWHrOOWcHgPQnd+7cplVH6SgtnYjQSXN3dCJCgHl4YAu9e/c262gl9xyA9GX9+vXy7LPPymOPPWZaflq1aiX79+/3dbXgB2jhge1pd5Zz3g4A6c/atWtNF5bSSQbnzZsna9asMQsG//zzz/LHH3/4uorwAyQtw9KaN28u9evXl9q1a8vVq1dl8+bNHud1+Kr+N9igQQPZsGGDz+oJIHXpQAXN5WEWdTjRwgNL0/ycEiVKmKTlzJkzm/tOmtwYFRUlXbp0IdgBLCY6OtrXVYCfoYUHttC2bVvT5E3TNmCtaSe8wbQTULTwwBamTp3q6yoASEVJTTXhjmknoGjhga0w9TwA2JfPp3tm4xow9TzvAb4HeA8k9z1QpEgRR8GCBXnv8N5xeHMNmIcHtpl6/vnnn5dHHnlEhg8fLn379jVN4gMGDJAjR47It99+6+sqAkim7t27S/v27V37PXr0kI4dO3IdES8CHojdp54/fPiwmXoeQPpWuHBh020NxIeAB7aZev7s2bOuqefdvxSZeh4ArI+AB7bD1PMAYD8MS4ctMPU8YE3dunWTZs2amfvFixeXmzdvuvadRo0axdQUYFg67Iup54H0P6GoN/l3U6ZMYdJREPAAAADro0sLlsXU8wAAJwIeWBZTzwMAnFhaAgAAWB7D0gEAgOXRpQXLIocHAOBEwAPLIocHsI/AwEB55ZVXpGHDhlKgQAE5fvy4zJ492wxJBxQ5PACAdC0oKEiWLl0qERERMmfOHDl9+rRZV6tp06Yyf/58ad26ta+rCD9ACw8AIF3TgCY8PNzMtBwZGek6XrRoUVm3bp3UqVNHVq5c6dM6wvcIeGD5HJ7p06ebWZX1fkK0jP6HCCD9qVixokyePNkj2FGHDh0y3Vp6noAHBDywfA5P1qxZk8zn0TIA0qeLFy9KtWrV4j1XqlQp/pmBQQ4PbCEsLEzu3LljvhiTcw6A/ytSpIjs2rVLxo4dKxMmTJCzZ8+af3DeeOMNadSokZQsWZLPN5iHB/bQu3dvM4IjuecA+L8jR46YwKZu3bqyYcMGs7969WopUaKEPPnkkwQ7MOjSgu1pd9aVK1dsfx2A9ExzdCpUqGCGpDuHpWtLD+BEwANLa968udSvX19q164tV69ejZPHkz17dnn22Wdl3LhxPqsjgHvz5ptvStmyZWX58uVm27x5M5cUcRDwwNI0P0ebtTVpOXPmzOa+k8PhkKioKOnSpYtpBgeQPm3dulVq1Kghw4YNM607u3fvdgU/up05c8bXVYQfIGkZttC2bVu5dOmS/PHHH76uCoD7qHTp0iaXR7d69epJvnz5TPLyqFGjuO42x+KhsIWpU6eaURy5cuVyzcyqzeCfffaZR6sPgPQrODjYtOrmyZPHbNmyZZODBw/KiRMnfF01+AkHG9fA6u+BsLAwx7Zt2xw5c+Y0+3379nVERkY6Vq9e7Th58qQjc+bMPq8jG9eA90DK3gNNmjRxLFy40HHlyhXHgQMHHGPHjnV06tTJUahQIa4pnyuH2zXgS4ZrYP33QJcuXRxffvmla3/Xrl2Ohg0bmvtLlixxtGrVyud1ZOMa8B5I2Xtg8ODBDjVjxgzHM88848idOzfXks+TI/Y1oEsLtlCwYEHXtPOa1Kjr7ixbtszsa1dX/vz5fVxDACk1YMAAMw+PfpbfeecdOXnypGzZskWGDx8uLVu2NF1bgCIS5hpY/j3QoUMHx6ZNmxz58+d3DBw40DFz5kzXOW0Kr1+/vs/ryMY14D2QOu+BLFmyOF577TXHoUOHTMtPr169uLbC54uAhzeBLb4IQkJCHKtWrTJfflFRUY6qVaua42XKlHFs2bLFERgY6PM6snENeA+k/D1QsGBB84/Nd99959i/f7/5rB8/ftzx888/O6pUqcK1FT5fDEuHrTz00ENy7tw518zKOhFhQECAHDt2zNdVA5BM/fr1M13V2iX9wQcfmNFYK1ascM2/s2/fPq4pXAh4AADp0uDBg+X06dOyaNEiiYmJIcBBophpGZbVokULadiwoUyfPl1CQ0PN/YRomaVLl6Zp/QCk3kzLQFIIeGBZupyEdlnp4qDO+wnRMgDSn5IlS0qDBg0SLbN37166rWGQzMU14D3Ae4D3AO+BdDv/TlIYpeX735U/bLTwAADSrU8++US+++67RMtcuHAhzeoD/0XAA1vQlZR79uwpVatWNZOQ6Rfg2rVrTdLjtm3bfF09ACl08eJFOXLkCNcPSSLggeW1b99eJk6cKDt37pQ5c+ZIVFSUWWBQk5jXr18vTZo0cc26DACwJgIeWFqmTJnk66+/lt69e8sXX3zhcU7n39FjY8aMkVKlSvmsjgBS5sCBA3RXIVl8nkjExjW4X++Bpk2bOjZu3JjgeZ1h+ejRo46IiAjeh7wPeQ/wHuA9INa9BiweCksrV65covPr3L1718zMWr58+TStFwAgbRHwwNJy5szpWiU9IWfPnjXlAADWRcADS8uQIYNpxUmMng8ODk6zOgEA0h5Jy7C8bt26SbNmzRI8X7x4cRkxYkSa1gkAkLYIeGBpGzZsMEPQE3P48GHZvn17mtUJAJD2WC0dAABYHjk8AADA8gh4AACA5RHwAAAAyyPgAQAAlkfAAwAALI+ABwAAWB4BDwAAsDwCHgAAYHkEPAAAwPIIeAAAgFjd/wVPXeIVhynE4wAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# Compare operating costs (per year)\n", "\n", @@ -465,9 +2208,76 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Costscapitaloperating
Distillation45.553829427.596731
Two Flash39.601876419.122339
\n", + "
" + ], + "text/plain": [ + "Costs capital operating\n", + "Distillation 45.553829 427.596731\n", + "Two Flash 39.601876 419.122339" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAHvCAYAAABQTQWGAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOyVJREFUeJzt3Qd40+X+//93W1pEaJlSoEyZhyUoyFAQBARBZCkOQIGjMhQXKoILxzmAylBQ4QgoIoKIAoIoKFPZQ7HsvUcBmWVD/tf7/v6TX1M6krY0zf15Pq4rVzPupHc+SZpX7xkiIi4BAACwWGigKwAAAHC9EXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AC4rj788EN57rnnsuzjOdnLL78sPXv2lKwiJCRERo4cKU2aNAl0VWChEFZaBnzXq1cvqVu3rjz66KPicl27SPmIESPkn3/+kTfffPOa+yi9z9mzZ+XYsWOybt06+eWXX+TIkSMp/s5PPvlE8uXLJ//5z3/MfVKjYaB27dqpltu1a5f07ds3xTIff/yxbN26VYYPHy5ptXHjRlPvBx98MMVy77zzjpQtW9Zz+fz587J9+3b57rvvZPPmzX4/Xnql9blHRkZK69atpUaNGpI7d26Ji4szz+OHH35I9bXOzLpWqVJF1qxZI3feeacsX75c2rVrJw888ECq97ty5Yp07NjR59fL3+Py1ltvSadOneRf//qXXLp0yefnA6SGFh7ADxpcHn74YQkNTfqj06pVq2v+O3Xf58cff5Tp06fLokWL5OTJk/Lvf/9b9u3bZ76kbrjhhiQfT4OL/geuX0RPP/20T3VcuXKlTJs2zXPauXOn+f1nzpzxun7+/PmpPlbLli09Ye160+OmJ3f9Vq1aZX5/bGysPP7445LZ0vLcNQjv3r1bevfuLYcPH5a5c+ean507d5a9e/ean1mlru+99578/vvvJuyoTZs2eb0/9H2q75u8efN6Xa/vYX9fL3+Oy7BhwyQmJkaeeOKJDDk2QEL6byonjgHvAR/eAxMnTnSpsLCwJG/fu3eva+nSpT7f54EHHnBdunTJNWXKlCQfb/To0eYxP/zwQ9eJEydcN954o9+vU9OmTc3v79atm9/33blzp6l/ej4fGzdudH333XepltPjps814XURERGurVu3uk6ePOnKnj27X4+X3pO/z71du3bmOA8bNizJ27t37+56/fXXs0Rdixcv7rp8+bLrscceS7ZMTEyMeT7Dhw9P1+uVluMyefJkV2xs7HV/jTmJo45BNq/oAyBTTZkyRe666y555plnpH79+ua/ardcuXLJQw89JO+//76MHz9enn/+eWnfvr18+eWXGfK7S5UqZbomSpcubVp/tMVHuxfcXXUTJ06Um266SerUqWPOJ+4Ge+ONN6RixYqebg7tlpg3b57MmDFDMsrFixfNYz711FNSvnx5+fvvv5Ms52tdPvvsM1m7dq2MHTvWtCBo94qWHT16tOkSckvtuScWHh4uH330kelue/HFF5Mso2NToqKi/HoN3F1B2sVTqVIlM8ZFu/O++uorUz4tdVX6vgoLC8vQ1yqp10uPR1qOi7aGapeldrtpixGQEejSAgJswoQJnu6wxN0A2bNnN1/G+gU2e/ZsefLJJzPkd+pYig0bNpiQtWzZMjPu6IsvvpDffvtNIiIiTBntptDxRvv370+yG+yPP/7wXD9nzhy5fPmyfP311/L5559LRtLgp86dO5dsGV/ros9bu34mTZok0dHRpjunQYMGpjumZMmSnnKpPffE9DhqN8w333wjV69eTbbcqVOn/HoN8ufPbwJaly5dTGhYvXq1lCtXzoy9cR8Xf+uq9Dlv2bJFjh8/Lhkt4euVluOili5dan42bNgww+sHZwt4MxMnjkGwvAfc3VOTJk0y5xOf4uPj/erS0lOePHnM7TNmzPC6fsWKFaZp3325RYsWplzFihXT1aWlv0+7HH755RdXSEiIp1y9evVMuf79+6e5q6R169bmMapWrZohXVrlypVznTp1yrVp0ya/Hy+puhw8eNB15swZV61atTzXRUVFuU6fPu0aMWKE1/39ee7PPfec+V36O30p7+tr0LlzZ3M5Ojra6/758+d3hYeHp/l10vKzZs1KsUxaurQSv17+Hhf3SY/JlStXXKNGjfLrfpw4BpLCMaBLC0gDHbiZ1H+saZlO6265uPHGGz3X3XLLLVKzZk155ZVXPNfNmjXLDEDWrpjkugd80aJFC9OFoINDE3ad6ADWFStWmJal/v37p/o42r2ig1S1S65gwYKSLVs2z3OoWrVqst1PKdHZaO5uGW3d0BlE+py1Cyaj6qJdQu6Buu7WBX3e1apVk7TKmTNnqq1Q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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# Compare total costs (capital costs and operating costs)\n", "\n", @@ -507,9 +2317,18 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Two flash case over one year: $459K / 4477 kmol benzene = $102.45 per kmol benzene produced\n", + "Distillation case over one year: $473K / 5108 kmol benzene = $92.63 per kmol benzene produced\n" + ] + } + ], "source": [ "two_flash_cost = value(1e3 * sum(two_flash_totcost[idx] for idx in two_flash_totcost))\n", "two_flash_prod = value(\n", @@ -554,7 +2373,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.13.0" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_doc.ipynb b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_doc.ipynb index 050e579a..170e401e 100644 --- a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_doc.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_doc.ipynb @@ -1,1868 +1,2381 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "# HDA Flowsheet Costing\n", - "Maintainer: Brandon Paul \n", - "Author: Brandon Paul \n", - "Updated: 2023-06-01 \n", - "\n", - "\n", - "## Note\n", - "\n", - "This example will demonstrate adding capital and operating costs to the two HDA examples, the basic [HDA with Flash](../tut/hda_flowsheet_solution_doc.md) and a comparison with the HDA with Distillation.\n", - "\n", - "\n", - "## Learning outcomes\n", - "\n", - "- Import external pre-built steady-state flowsheets using the IDAES unit model library\n", - "- Define and add costing blocks using the IDAES Process Costing Framework\n", - "- Formulate and solve a process economics optimization problem\n", - " - Defining an objective function\n", - " - Setting variable bounds\n", - " - Adding additional constraints \n", - "\n", - "\n", - "## Problem Statement\n", - "\n", - "Hydrodealkylation is a chemical reaction that often involves reacting\n", - "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", - "simpler aromatic hydrocarbon devoid of functional groups. In this\n", - "example, toluene will be reacted with hydrogen gas at high temperatures\n", - " to form benzene via the following reaction:\n", - "\n", - "**C6H5CH3 + H2 → C6H6 + CH4**\n", - "\n", - "\n", - "This reaction is often accompanied by an equilibrium side reaction\n", - "which forms diphenyl, which we will neglect for this example.\n", - "\n", - "This example is based on the 1967 AIChE Student Contest problem as\n", - "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", - "McGraw-Hill.\n", - "\n", - "Users may refer to the prior examples linked at the top of this notebook for detailed process descriptions of the two HDA configurations. As before, the properties required for this module are defined in\n", - "\n", - "- `hda_ideal_VLE.py`\n", - "- `idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE`\n", - "- `hda_reaction.py`\n", - "\n", - "Additionally, we will be importing externally-defined flowsheets for the two HDA configurations from\n", - "\n", - "- `hda_flowsheets_for_costing_notebook.py`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Import and run HDA Flowsheets\n", - "First, we will generate solved flowsheets for each HDA model. The external scripts build and set inputs for the flowsheets, initialize unit models and streams, and solve the flowsheets before returning the model objects. Note that the HDA flowsheets contain all unit models and stream connections, and no costing equations." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The flowsheet utilizes the Wegstein method to iteratively solve circular dependencies such as recycle streams, and is intended to approach a feasible solution. As such, the calls below will fail to converge after 3 iterations and pass to IPOPT to obtain an optimal solution as expected:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Building flowsheet...\n", - "\n", - "Setting inputs...\n", - "\n", - "Initializing flowsheet...\n", - "\n", - "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", - "\n", - "fs.s03\n", - "fs.H101\n", - "fs.R101\n", - "fs.F101\n", - "fs.S101\n", - "fs.C101\n", - "fs.M101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:47 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.F102.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.F102: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:48 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:49 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:50 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:51 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:52 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:52 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:52 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:52 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: Wegstein failed to converge in 3 iterations\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:52 [INFO] idaes.init.fs.F102.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:23:52 [INFO] idaes.init.fs.F102: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving flowsheet...\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=5000\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1031\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 934\n", - "\n", - "Total number of variables............................: 340\n", - " variables with only lower bounds: 0\n", - " variables with lower and upper bounds: 146\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 340\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 6.60e+04 0.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 8.69e+03 1.42e+03 -1.0 2.00e+04 - 9.71e-01 4.67e-01H 1\n", - " 2 0.0000000e+00 3.05e+03 1.56e+03 -1.0 1.60e+04 - 9.79e-01 4.90e-01h 1\n", - " 3 0.0000000e+00 1.58e+03 1.55e+05 -1.0 1.41e+04 - 9.90e-01 4.99e-01h 1\n", - " 4 0.0000000e+00 5.49e+02 8.87e+08 -1.0 8.43e+03 - 1.00e+00 9.57e-01h 1\n", - " 5 0.0000000e+00 4.25e+03 2.87e+10 -1.0 8.02e+02 - 1.00e+00 9.90e-01h 1\n", - " 6 0.0000000e+00 2.25e+03 1.51e+10 -1.0 8.39e+00 - 1.00e+00 1.00e+00h 1\n", - " 7 0.0000000e+00 2.27e+01 1.40e+08 -1.0 2.45e-03 - 1.00e+00 1.00e+00f 1\n", - " 8 0.0000000e+00 2.45e-03 1.23e+04 -1.0 2.38e-05 - 1.00e+00 1.00e+00h 1\n", - " 9 0.0000000e+00 7.45e-09 3.06e-01 -2.5 9.06e-08 - 1.00e+00 1.00e+00h 1\n", - "Cannot recompute multipliers for feasibility problem. Error in eq_mult_calculator\n", - "\n", - "Number of Iterations....: 9\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 2.8284422320850682e+05 2.8284422320850682e+05\n", - "Constraint violation....: 2.9103830456733704e-11 7.4505805969238281e-09\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 2.9103830456733704e-11 2.8284422320850682e+05\n", - "\n", - "\n", - "Number of objective function evaluations = 11\n", - "Number of objective gradient evaluations = 10\n", - "Number of equality constraint evaluations = 11\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 10\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 9\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.008\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Complete.\n", - "\n" - ] - } - ], - "source": [ - "# Source file for prebuilt flowsheets\n", - "from hda_flowsheets_for_costing_notebook import hda_with_flash\n", - "\n", - "# Build hda model with second flash unit and return model object\n", - "m = hda_with_flash(tee=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## IDAES Process Costing Framework\n", - "IDAES provides a library of capital costing correlations based on those in the following source:\n", - "\n", - "*Process and Product Design Principles: Synthesis, Analysis, and Evaluation*. Seider, Seader, Lewin, Windagdo, 3rd Ed. John Wiley and Sons Chapter 22. Cost Accounting and Capital Cost Estimation 22.2 Cost Indexes and Capital Investment.\n", - "\n", - "Currently, IDAES supports calculation of capital costing for a wide array of unit operations, vesseel sizing and material properties, and specific unit options such as column tray types and heat exchanger configurations. Users may find further information on specific costing methods and options in the IDAES Process Costing Framework documentation (link pending).\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add Operating Cost Equations\n", - "Before adding capital costing blocks, we will add operating cost equations taken from the basic [HDA with Flash](../tut/hda_flowsheet_solution_doc.md) and the HDA with Distillation examples. The examples assume constant cooling and heating coefficients over an annual cost basis. The IDAES Generic Costing Framework does not currently support variable cost calculations." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Required imports\n", - "from pyomo.environ import Expression\n", - "\n", - "# Operating costs for HDA with second flash (model m)\n", - "m.fs.cooling_cost = Expression(\n", - " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", - ")\n", - "m.fs.heating_cost = Expression(\n", - " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", - ")\n", - "m.fs.operating_cost = Expression(\n", - " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add Capital Costing\n", - "Below, we will add add capital costing blocks to the imported flowsheets and evaluate the economic impact of replacing the second Flash with a Distillation column. First, let's import and define the main flowsheet costing block:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Import costing methods - classes, heaters, vessels, compressors, columns\n", - "from idaes.models.costing.SSLW import (\n", - " SSLWCosting,\n", - " SSLWCostingData,\n", - ")\n", - "from idaes.core import UnitModelCostingBlock\n", - "\n", - "# Costing block\n", - "m.fs.costing = SSLWCosting()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will build the relevant costing blocks for the equipment we wish to cost. Note how the costing block, methods and flags are passed as arguments in the costing block call itself. Each unit model will have a single costing block, but each flowsheet model (m and n) will also have a single costing block for flowsheet-level properties.\n", - "\n", - "Users should note that IDAES costing methods support a wide array of heating sources (e.g. fired, steam boiler, hot water) and do not support direct capital costing of coolers. If users wish to cost Heater units acting as coolers, it is necessary to cost a \"dummy\" [0D shell and tube exchanger](https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/heat_exchanger.html) with appropriate aliased hot stream properties and proper cooling water properties. This is not demonstrated here, as the HDA examples take advantage of Flash and Condenser operations to recover liquid product.\n", - "\n", - "Capital costing is independent of unit model connections, and building cost equations may be done piecewise in this fashion. Default options are passed explicitly to demonstrate proper syntax and usage. Now that all required properties are defined, let's cost our models connecting costing blocks, methods and unit models in each flowsheet." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Flexibility of Costing Block Definitions\n", - "IDAES supports many ways to define batches of costing blocks, and several are shown in the example. Users may employ whichever method fits their modeling needs for explicit or concise code. In the code below, note how the unit model itself is never passed to the costing method; when the full model is executed, the costing block will automatically connect its parent block with child equation blocks.\n", - "\n", - "`Compressor` unit models with isothermal or adiabatic thermodynamics are too simple to cost and are therefore excluded from the economic analysis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's define costing for the heater unit:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.costing.SSLW import (\n", - " HeaterMaterial,\n", - " HeaterSource,\n", - ")\n", - "\n", - "# Costing for heater - m.fs.H101\n", - "m.fs.H101.costing = UnitModelCostingBlock(\n", - " flowsheet_costing_block=m.fs.costing,\n", - " costing_method=SSLWCostingData.cost_fired_heater,\n", - " costing_method_arguments={\n", - " \"material_type\": HeaterMaterial.CarbonSteel,\n", - " \"heat_source\": HeaterSource.Fuel,\n", - " },\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The costing module provides a `unit_mapping` dictionary linking generic unit model classes with recommended costing methods. In this example, StoichiometricReactor and Flash vessels utilize different vessel costing methods with similar arguments. The diameter and length attributes need to exist in order to cost vessel sizing and material requirements, and we add them if they don't exist already. The `unit_mapping` method provides an opportunity to automatically select the correct vessel orientation (vertical or horizontal) based on the unit type; passing a `StoichiometricReactor` or `PFR` class object will call the `cost_horizontal_vessel` method, while passing a `Flash` or `CSTR` class object will call the `cost_vertical_vessel` method.\n", - "\n", - "All vessels are assigned costing succinctly via a loop below - users may define each block individually if desired:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.costing.SSLW import (\n", - " VesselMaterial,\n", - " TrayType,\n", - " TrayMaterial,\n", - ")\n", - "\n", - "from idaes.core.util.constants import Constants\n", - "from pyomo.environ import Var, Constraint, units as pyunits, Param, value\n", - "from idaes.models.unit_models import StoichiometricReactor, Flash\n", - "\n", - "# Map unit models to unit classes\n", - "# Will pass to unit_mapping which calls costing methods based on unit class\n", - "unit_class_mapping = {\n", - " m.fs.R101: StoichiometricReactor,\n", - " m.fs.F101: Flash,\n", - " m.fs.F102: Flash,\n", - "}\n", - "\n", - "# Costing for vessels - m.fs.R101, m.fs.F101, m.fs.F102\n", - "\n", - "# Loop over units\n", - "for unit in [m.fs.R101, m.fs.F101, m.fs.F102]:\n", - " # Get correct unit class for unit model\n", - " unit_class = unit_class_mapping[unit]\n", - "\n", - " # Add dimension variables and constraint if they don't exist\n", - " if not hasattr(unit, \"diameter\"):\n", - " unit.diameter = Var(initialize=1, units=pyunits.m)\n", - " if not hasattr(unit, \"length\"):\n", - " unit.length = Var(initialize=1, units=pyunits.m)\n", - " if hasattr(unit, \"volume\"): # if volume exists, set diameter from volume\n", - " unit.volume_eq = Constraint(\n", - " expr=unit.volume[0] == unit.length * unit.diameter**2 * 0.25 * Constants.pi\n", - " )\n", - " else: # fix diameter directly\n", - " unit.diameter.fix(0.2214 * pyunits.m)\n", - " # Either way, fix L/D to calculate L from D\n", - " unit.L_over_D = Constraint(expr=unit.length == 3 * unit.diameter)\n", - "\n", - " # Define vessel costing\n", - " unit.costing = UnitModelCostingBlock(\n", - " flowsheet_costing_block=unit.parent_block().costing, # e.g. m.fs.R101.costing\n", - " costing_method=SSLWCostingData.unit_mapping[\n", - " unit_class\n", - " ], # e.g. cost_vertical_vessel()\n", - " costing_method_arguments={\n", - " \"material_type\": VesselMaterial.CarbonSteel,\n", - " \"shell_thickness\": 1.25 * pyunits.inch,\n", - " },\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Solve Flowsheet Costing Blocks\n", - "Now, we may solve the full flowsheet for all costing blocks:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Eefine solver\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", - "\n", - "# Check that the degrees of freedom is zero\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "\n", - "assert degrees_of_freedom(m) == 0" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: nlp_scaling_method=gradient-based\n", - "tol=1e-06\n", - "max_iter=200\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1067\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 942\n", - "\n", - "Total number of variables............................: 358\n", - " variables with only lower bounds: 15\n", - " variables with lower and upper bounds: 146\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 358\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 1.00e+05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 8.81e+04 5.49e+03 -1.0 9.20e+04 - 2.62e-01 1.20e-01h 1\n", - " 2 0.0000000e+00 6.34e+04 2.46e+03 -1.0 8.10e+04 - 5.83e-01 2.87e-01h 1\n", - " 3 0.0000000e+00 3.40e+04 5.65e+03 -1.0 5.80e+04 - 5.72e-01 4.86e-01h 1\n", - " 4 0.0000000e+00 2.33e+04 5.28e+05 -1.0 3.01e+04 - 7.04e-01 5.09e-01h 1\n", - " 5 0.0000000e+00 1.13e+04 2.99e+09 -1.0 1.49e+04 - 8.02e-01 9.65e-01h 1\n", - " 6 0.0000000e+00 5.50e+03 1.54e+09 -1.0 8.18e+02 - 9.90e-01 6.10e-01h 1\n", - " 7 0.0000000e+00 5.23e+03 1.44e+09 -1.0 3.84e+02 - 9.92e-01 5.07e-02h 1\n", - " 8 0.0000000e+00 5.22e+03 1.44e+09 -1.0 3.70e+02 - 1.00e+00 5.85e-04h 1\n", - " 9r 0.0000000e+00 5.22e+03 1.00e+03 2.3 0.00e+00 - 0.00e+00 3.66e-07R 5\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10r 0.0000000e+00 6.47e+04 1.34e+04 2.3 1.78e+05 - 2.30e-03 1.09e-03f 1\n", - " 11r 0.0000000e+00 3.63e+04 4.53e+04 2.3 7.67e+03 - 7.32e-02 3.13e-03f 1\n", - " 12r 0.0000000e+00 3.93e+04 4.20e+04 2.3 6.14e+03 - 6.79e-02 1.14e-01f 1\n", - " 13r 0.0000000e+00 3.99e+04 2.20e+04 2.3 6.23e+02 - 4.86e-01 3.05e-01f 1\n", - " 14r 0.0000000e+00 5.25e+04 1.67e+04 2.3 1.89e+03 - 2.37e-01 1.00e+00f 1\n", - " 15r 0.0000000e+00 5.74e+04 8.19e+02 2.3 1.50e+03 - 9.73e-01 7.07e-01f 1\n", - " 16r 0.0000000e+00 5.79e+04 7.74e+02 0.9 5.93e+02 - 9.40e-01 5.52e-01f 1\n", - " 17r 0.0000000e+00 5.77e+04 4.91e+03 0.9 4.87e+02 - 9.04e-01 4.24e-01f 1\n", - " 18r 0.0000000e+00 6.06e+04 1.62e+03 0.9 5.45e+02 - 1.00e+00 6.92e-01f 1\n", - " 19r 0.0000000e+00 6.61e+04 2.32e+02 0.9 2.04e+02 - 1.00e+00 9.52e-01f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20r 0.0000000e+00 7.62e+04 1.03e+03 0.2 1.71e+02 - 8.32e-01 8.32e-01f 1\n", - " 21r 0.0000000e+00 7.57e+04 8.29e+01 0.2 6.76e+02 - 1.00e+00 1.00e+00f 1\n", - " 22r 0.0000000e+00 7.23e+04 4.74e+01 -0.5 1.37e+02 - 1.00e+00 9.01e-01f 1\n", - " 23r 0.0000000e+00 5.71e+04 3.30e+01 -0.5 7.91e+02 - 1.00e+00 1.00e+00f 1\n", - " 24r 0.0000000e+00 5.85e+04 6.01e-01 -0.5 1.26e+02 - 1.00e+00 1.00e+00h 1\n", - " 25r 0.0000000e+00 4.88e+04 1.78e+02 -2.8 4.53e+02 - 9.80e-01 7.63e-01f 1\n", - " 26r 0.0000000e+00 2.12e+04 2.63e+02 -2.8 2.29e+03 - 4.88e-01 2.16e-01f 1\n", - " 27r 0.0000000e+00 2.05e+04 5.27e+02 -2.8 3.17e+03 - 1.00e+00 3.36e-01f 1\n", - " 28r 0.0000000e+00 2.00e+04 7.36e+02 -2.8 3.93e+03 - 3.18e-02 1.06e-01f 1\n", - " 29r 0.0000000e+00 7.19e+03 7.22e+02 -2.8 4.19e+03 - 1.00e+00 3.22e-01f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30r 0.0000000e+00 8.95e+03 2.50e+03 -2.8 6.03e+02 - 1.00e+00 7.72e-01f 1\n", - " 31r 0.0000000e+00 5.53e+03 1.10e+03 -2.8 1.82e+03 - 7.92e-01 3.40e-01f 1\n", - " 32r 0.0000000e+00 3.65e+03 7.38e+02 -2.8 1.83e+03 - 6.45e-01 5.76e-01f 1\n", - " 33r 0.0000000e+00 4.19e+02 7.29e+02 -2.8 8.86e+02 - 6.85e-01 8.10e-01f 1\n", - " 34r 0.0000000e+00 2.59e+02 3.88e+02 -2.8 8.93e+01 - 1.00e+00 1.00e+00f 1\n", - " 35r 0.0000000e+00 2.37e+02 3.62e+02 -2.8 8.07e+00 - 1.00e+00 1.00e+00h 1\n", - " 36r 0.0000000e+00 2.37e+02 1.60e+00 -2.8 2.49e+00 - 1.00e+00 1.00e+00h 1\n", - " 37r 0.0000000e+00 2.37e+02 3.54e-02 -2.8 6.73e-02 - 1.00e+00 1.00e+00h 1\n", - " 38r 0.0000000e+00 2.40e+02 6.94e+02 -4.3 1.16e+02 - 1.00e+00 5.13e-01f 1\n", - " 39r 0.0000000e+00 1.40e+02 1.92e+03 -4.3 6.99e+01 - 9.98e-01 4.06e-01f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 40r 0.0000000e+00 8.34e+01 2.11e+03 -4.3 4.21e+01 - 1.00e+00 6.67e-01f 1\n", - " 41r 0.0000000e+00 2.54e+01 6.31e+02 -4.3 2.23e+01 - 7.35e-01 1.00e+00f 1\n", - " 42 0.0000000e+00 2.26e+01 1.16e+07 -1.0 4.76e+01 - 9.90e-01 1.25e-01h 4\n", - " 43 0.0000000e+00 2.00e+01 5.45e+06 -1.0 4.09e+01 - 9.90e-01 1.25e-01h 4\n", - " 44 0.0000000e+00 1.59e+01 4.92e+06 -1.0 3.49e+01 - 9.91e-01 2.50e-01h 3\n", - " 45 0.0000000e+00 1.23e+01 4.33e+06 -1.0 2.41e+01 - 1.00e+00 2.50e-01h 3\n", - " 46 0.0000000e+00 7.56e+00 5.75e+06 -1.0 1.54e+01 - 1.00e+00 5.00e-01h 2\n", - " 47 0.0000000e+00 3.06e+01 1.36e+07 -1.0 1.62e+00 - 1.00e+00 1.00e+00h 1\n", - " 48 0.0000000e+00 3.18e-04 1.31e+03 -1.0 3.34e+01 - 1.00e+00 1.00e+00h 1\n", - " 49 0.0000000e+00 2.24e-08 3.21e-01 -3.8 1.06e-07 - 1.00e+00 1.00e+00h 1\n", - "Cannot recompute multipliers for feasibility problem. Error in eq_mult_calculator\n", - "\n", - "Number of Iterations....: 49\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 1.5041240304748950e+04 1.5041240304748950e+04\n", - "Constraint violation....: 2.9103830456733704e-11 2.2351741790771484e-08\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 2.9103830456733704e-11 1.5041240304748950e+04\n", - "\n", - "\n", - "Number of objective function evaluations = 74\n", - "Number of objective gradient evaluations = 19\n", - "Number of equality constraint evaluations = 74\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 51\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 49\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.061\n", - "Total CPU secs in NLP function evaluations = 0.003\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - } - ], - "source": [ - "# Check physical units consistency, solve and check solver status\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.util.check_units import assert_units_consistent\n", - "\n", - "assert_units_consistent(m)\n", - "results = solver.solve(m, tee=True, symbolic_solver_labels=True)\n", - "assert results.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For comparison, we will call and build the HDA flowsheet replacing the second `Flash` with a `TrayColumn` distillation unit model. The flowsheet costing occurs in the external script `hda_flowsheets_for_costing_notebook.py` and is not shown here:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Building flowsheet...\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Setting inputs...\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initializing flowsheet...\n", - "\n", - "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: Wegstein failed to converge in 3 iterations\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving flowsheet...\n", - "\n", - "WARNING: model contains export suffix\n", - "'fs.H102.control_volume.properties_out[0.0].scaling_factor' that contains 1\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.H102.control_volume.scaling_factor'\n", - "that contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.F101.control_volume.properties_out[0.0].scaling_factor' that contains 26\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.F101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.F101.control_volume.scaling_factor'\n", - "that contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.R101.control_volume.properties_out[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.R101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.R101.control_volume.scaling_factor'\n", - "that contains 2 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H101.control_volume.properties_out[0.0].scaling_factor' that contains 26\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Adding distillation column and resolving flowsheet...\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.D101.condenser.control_volume.properties_out[0.0].scaling_factor' that\n", - "contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [ + "header", + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H102.control_volume.properties_out[0.0].scaling_factor' that contains 1\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# HDA Flowsheet Costing\n", + "Maintainer: Brandon Paul \n", + "Author: Brandon Paul \n", + "Updated: 2023-06-01 \n", + "\n", + "\n", + "## Note\n", + "\n", + "This example will demonstrate adding capital and operating costs to the two HDA examples, the basic [HDA with Flash](../tut/hda_flowsheet_solution_doc.md) and a comparison with the HDA with Distillation.\n", + "\n", + "\n", + "## Learning outcomes\n", + "\n", + "- Import external pre-built steady-state flowsheets using the IDAES unit model library\n", + "- Define and add costing blocks using the IDAES Process Costing Framework\n", + "- Formulate and solve a process economics optimization problem\n", + " - Defining an objective function\n", + " - Setting variable bounds\n", + " - Adding additional constraints \n", + "\n", + "\n", + "## Problem Statement\n", + "\n", + "Hydrodealkylation is a chemical reaction that often involves reacting\n", + "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", + "simpler aromatic hydrocarbon devoid of functional groups. In this\n", + "example, toluene will be reacted with hydrogen gas at high temperatures\n", + " to form benzene via the following reaction:\n", + "\n", + "**C6H5CH3 + H2 \u2192 C6H6 + CH4**\n", + "\n", + "\n", + "This reaction is often accompanied by an equilibrium side reaction\n", + "which forms diphenyl, which we will neglect for this example.\n", + "\n", + "This example is based on the 1967 AIChE Student Contest problem as\n", + "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", + "McGraw-Hill.\n", + "\n", + "Users may refer to the prior examples linked at the top of this notebook for detailed process descriptions of the two HDA configurations. As before, the properties required for this module are defined in\n", + "\n", + "- `hda_ideal_VLE.py`\n", + "- `idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE`\n", + "- `hda_reaction.py`\n", + "\n", + "Additionally, we will be importing externally-defined flowsheets for the two HDA configurations from\n", + "\n", + "- `hda_flowsheets_for_costing_notebook.py`" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.H102.control_volume.scaling_factor'\n", - "that contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import and run HDA Flowsheets\n", + "First, we will generate solved flowsheets for each HDA model. The external scripts build and set inputs for the flowsheets, initialize unit models and streams, and solve the flowsheets before returning the model objects. Note that the HDA flowsheets contain all unit models and stream connections, and no costing equations." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.F101.control_volume.properties_out[0.0].scaling_factor' that contains 26\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The flowsheet utilizes the Wegstein method to iteratively solve circular dependencies such as recycle streams, and is intended to approach a feasible solution. As such, the calls below will fail to converge after 3 iterations and pass to IPOPT to obtain an optimal solution as expected:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.F101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "fs.s03\n", + "fs.H101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n", + "2026-07-22 11:48:38 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "Solving flowsheet...\n", + "\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=5000\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1031\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 934\n", + "\n", + "Total number of variables............................: 340\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 146\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 340\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.60e+04 0.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 8.69e+03 1.42e+03 -1.0 2.00e+04 - 9.71e-01 4.67e-01H 1\n", + " 2 0.0000000e+00 3.05e+03 1.56e+03 -1.0 1.60e+04 - 9.79e-01 4.90e-01h 1\n", + " 3 0.0000000e+00 1.58e+03 1.55e+05 -1.0 1.40e+04 - 9.90e-01 4.99e-01h 1\n", + " 4 0.0000000e+00 5.49e+02 8.87e+08 -1.0 8.42e+03 - 1.00e+00 9.57e-01h 1\n", + " 5 0.0000000e+00 4.25e+03 2.87e+10 -1.0 8.02e+02 - 1.00e+00 9.90e-01h 1\n", + " 6 0.0000000e+00 2.25e+03 1.51e+10 -1.0 8.39e+00 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 2.27e+01 1.40e+08 -1.0 2.45e-03 - 1.00e+00 1.00e+00f 1\n", + " 8 0.0000000e+00 2.45e-03 1.23e+04 -1.0 2.39e-05 - 1.00e+00 1.00e+00h 1\n", + " 9 0.0000000e+00 2.24e-08 4.65e-01 -2.5 9.06e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 0.0000000e+00 2.24e-08 1.41e+05 -5.7 1.38e-07 - 1.00e+00 5.00e-01h 2\n", + " 11 0.0000000e+00 7.45e-09 5.56e-03 -5.7 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 12 0.0000000e+00 7.45e-09 2.47e-09 -5.7 9.00e-08 - 1.00e+00 1.00e+00h 1\n", + " 13 0.0000000e+00 2.24e-08 5.06e-07 -7.0 1.38e-07 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 13\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "Constraint violation....: 5.8207660913467407e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593319938534624e-14 2.8593319938534624e-14\n", + "Complementarity.........: 9.0909090909115134e-08 9.0909090909115134e-08\n", + "Overall NLP error.......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "\n", + "\n", + "Number of objective function evaluations = 17\n", + "Number of objective gradient evaluations = 14\n", + "Number of equality constraint evaluations = 17\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 14\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 13\n", + "Total seconds in IPOPT = 0.018\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Complete.\n", + "\n" + ] + } + ], + "source": [ + "# Source file for prebuilt flowsheets\n", + "from hda_flowsheets_for_costing_notebook import hda_with_flash\n", + "\n", + "# Build hda model with second flash unit and return model object\n", + "m = hda_with_flash(tee=True)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.F101.control_volume.scaling_factor'\n", - "that contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## IDAES Process Costing Framework\n", + "IDAES provides a library of capital costing correlations based on those in the following source:\n", + "\n", + "*Process and Product Design Principles: Synthesis, Analysis, and Evaluation*. Seider, Seader, Lewin, Windagdo, 3rd Ed. John Wiley and Sons Chapter 22. Cost Accounting and Capital Cost Estimation 22.2 Cost Indexes and Capital Investment.\n", + "\n", + "Currently, IDAES supports calculation of capital costing for a wide array of unit operations, vesseel sizing and material properties, and specific unit options such as column tray types and heat exchanger configurations. Users may find further information on specific costing methods and options in the IDAES Process Costing Framework documentation (link pending).\n" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.R101.control_volume.properties_out[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Operating Cost Equations\n", + "Before adding capital costing blocks, we will add operating cost equations taken from the basic [HDA with Flash](../tut/hda_flowsheet_solution_doc.md) and the HDA with Distillation examples. The examples assume constant cooling and heating coefficients over an annual cost basis. The IDAES Generic Costing Framework does not currently support variable cost calculations." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.R101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Required imports\n", + "from pyomo.environ import Expression\n", + "\n", + "# Operating costs for HDA with second flash (model m)\n", + "m.fs.cooling_cost = Expression(\n", + " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", + ")\n", + "m.fs.heating_cost = Expression(\n", + " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", + ")\n", + "m.fs.operating_cost = Expression(\n", + " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.R101.control_volume.scaling_factor'\n", - "that contains 2 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Capital Costing\n", + "Below, we will add add capital costing blocks to the imported flowsheets and evaluate the economic impact of replacing the second Flash with a Distillation column. First, let's import and define the main flowsheet costing block:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H101.control_volume.properties_out[0.0].scaling_factor' that contains 26\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Import costing methods - classes, heaters, vessels, compressors, columns\n", + "from idaes.models.costing.SSLW import (\n", + " SSLWCosting,\n", + " SSLWCostingData,\n", + ")\n", + "from idaes.core import UnitModelCostingBlock\n", + "\n", + "# Costing block\n", + "m.fs.costing = SSLWCosting()" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will build the relevant costing blocks for the equipment we wish to cost. Note how the costing block, methods and flags are passed as arguments in the costing block call itself. Each unit model will have a single costing block, but each flowsheet model (m and n) will also have a single costing block for flowsheet-level properties.\n", + "\n", + "Users should note that IDAES costing methods support a wide array of heating sources (e.g. fired, steam boiler, hot water) and do not support direct capital costing of coolers. If users wish to cost Heater units acting as coolers, it is necessary to cost a \"dummy\" [0D shell and tube exchanger](https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/heat_exchanger.html) with appropriate aliased hot stream properties and proper cooling water properties. This is not demonstrated here, as the HDA examples take advantage of Flash and Condenser operations to recover liquid product.\n", + "\n", + "Capital costing is independent of unit model connections, and building cost equations may be done piecewise in this fashion. Default options are passed explicitly to demonstrate proper syntax and usage. Now that all required properties are defined, let's cost our models connecting costing blocks, methods and unit models in each flowsheet." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Complete.\n", - "\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Flexibility of Costing Block Definitions\n", + "IDAES supports many ways to define batches of costing blocks, and several are shown in the example. Users may employ whichever method fits their modeling needs for explicit or concise code. In the code below, note how the unit model itself is never passed to the costing method; when the full model is executed, the costing block will automatically connect its parent block with child equation blocks.\n", + "\n", + "`Compressor` unit models with isothermal or adiabatic thermodynamics are too simple to cost and are therefore excluded from the economic analysis." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.D101.condenser.control_volume.properties_out[0.0].scaling_factor' that\n", - "contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define costing for the heater unit:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H102.control_volume.properties_out[0.0].scaling_factor' that contains 1\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from idaes.models.costing.SSLW import (\n", + " HeaterMaterial,\n", + " HeaterSource,\n", + ")\n", + "\n", + "# Costing for heater - m.fs.H101\n", + "m.fs.H101.costing = UnitModelCostingBlock(\n", + " flowsheet_costing_block=m.fs.costing,\n", + " costing_method=SSLWCostingData.cost_fired_heater,\n", + " costing_method_arguments={\n", + " \"material_type\": HeaterMaterial.CarbonSteel,\n", + " \"heat_source\": HeaterSource.Fuel,\n", + " },\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.H102.control_volume.scaling_factor'\n", - "that contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The costing module provides a `unit_mapping` dictionary linking generic unit model classes with recommended costing methods. In this example, StoichiometricReactor and Flash vessels utilize different vessel costing methods with similar arguments. The diameter and length attributes need to exist in order to cost vessel sizing and material requirements, and we add them if they don't exist already. The `unit_mapping` method provides an opportunity to automatically select the correct vessel orientation (vertical or horizontal) based on the unit type; passing a `StoichiometricReactor` or `PFR` class object will call the `cost_horizontal_vessel` method, while passing a `Flash` or `CSTR` class object will call the `cost_vertical_vessel` method.\n", + "\n", + "All vessels are assigned costing succinctly via a loop below - users may define each block individually if desired:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.F101.control_volume.properties_out[0.0].scaling_factor' that contains 26\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from idaes.models.costing.SSLW import (\n", + " VesselMaterial,\n", + " TrayType,\n", + " TrayMaterial,\n", + ")\n", + "\n", + "from idaes.core.util.constants import Constants\n", + "from pyomo.environ import Var, Constraint, units as pyunits, Param, value\n", + "from idaes.models.unit_models import StoichiometricReactor, Flash\n", + "\n", + "# Map unit models to unit classes\n", + "# Will pass to unit_mapping which calls costing methods based on unit class\n", + "unit_class_mapping = {\n", + " m.fs.R101: StoichiometricReactor,\n", + " m.fs.F101: Flash,\n", + " m.fs.F102: Flash,\n", + "}\n", + "\n", + "# Costing for vessels - m.fs.R101, m.fs.F101, m.fs.F102\n", + "\n", + "# Loop over units\n", + "for unit in [m.fs.R101, m.fs.F101, m.fs.F102]:\n", + " # Get correct unit class for unit model\n", + " unit_class = unit_class_mapping[unit]\n", + "\n", + " # Add dimension variables and constraint if they don't exist\n", + " if not hasattr(unit, \"diameter\"):\n", + " unit.diameter = Var(initialize=1, units=pyunits.m)\n", + " if not hasattr(unit, \"length\"):\n", + " unit.length = Var(initialize=1, units=pyunits.m)\n", + " if hasattr(unit, \"volume\"): # if volume exists, set diameter from volume\n", + " unit.volume_eq = Constraint(\n", + " expr=unit.volume[0] == unit.length * unit.diameter**2 * 0.25 * Constants.pi\n", + " )\n", + " else: # fix diameter directly\n", + " unit.diameter.fix(0.2214 * pyunits.m)\n", + " # Either way, fix L/D to calculate L from D\n", + " unit.L_over_D = Constraint(expr=unit.length == 3 * unit.diameter)\n", + "\n", + " # Define vessel costing\n", + " unit.costing = UnitModelCostingBlock(\n", + " flowsheet_costing_block=unit.parent_block().costing, # e.g. m.fs.R101.costing\n", + " costing_method=SSLWCostingData.unit_mapping[\n", + " unit_class\n", + " ], # e.g. cost_vertical_vessel()\n", + " costing_method_arguments={\n", + " \"material_type\": VesselMaterial.CarbonSteel,\n", + " \"shell_thickness\": 1.25 * pyunits.inch,\n", + " },\n", + " )" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.F101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solve Flowsheet Costing Blocks\n", + "Now, we may solve the full flowsheet for all costing blocks:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.F101.control_volume.scaling_factor'\n", - "that contains 1 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Define solver\n", + "from idaes.core.solvers import get_solver\n", + "\n", + "solver = get_solver(\"ipopt_v2\", options={\"max_iter\": 500})\n", + "\n", + "# Check that the degrees of freedom is zero\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "\n", + "assert degrees_of_freedom(m) == 0" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.R101.control_volume.properties_out[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.14.20: linear_solver=\"ma57\"\n", + "max_iter=500\n", + "nlp_scaling_method=\"gradient-based\"\n", + "tol=1e-06\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 604\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 569\n", + "\n", + "Total number of variables............................: 160\n", + " variables with only lower bounds: 10\n", + " variables with lower and upper bounds: 38\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 160\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.00e+05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (6534)\n", + " 1 0.0000000e+00 8.81e+04 5.45e+03 -1.0 9.27e+04 - 2.62e-01 1.20e-01h 1\n", + " 2 0.0000000e+00 6.34e+04 2.46e+03 -1.0 8.16e+04 - 9.83e-01 2.87e-01h 1\n", + " 3 0.0000000e+00 3.40e+04 1.76e+03 -1.0 5.81e+04 - 4.59e-01 4.86e-01h 1\n", + " 4 0.0000000e+00 2.33e+04 9.17e+04 -1.0 2.99e+04 - 7.04e-01 5.09e-01h 1\n", + " 5 0.0000000e+00 1.13e+04 7.52e+08 -1.0 1.47e+04 - 8.02e-01 9.65e-01h 1\n", + "Reallocating memory for MA57: lfact (7452)\n", + " 6 0.0000000e+00 5.50e+03 3.83e+08 -1.0 8.18e+02 - 9.90e-01 6.10e-01h 1\n", + " 7 0.0000000e+00 5.23e+03 3.45e+08 -1.0 3.84e+02 - 1.00e+00 5.07e-02h 1\n", + "Reallocating memory for MA57: lfact (8076)\n", + " 8 0.0000000e+00 5.22e+03 7.30e+08 -1.0 3.70e+02 - 1.00e+00 5.85e-04h 1\n", + " 9r 0.0000000e+00 5.22e+03 1.00e+03 2.3 0.00e+00 - 0.00e+00 3.66e-07R 5\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10r 0.0000000e+00 6.37e+04 2.29e+04 2.3 2.43e+07 - 1.50e-03 9.91e-04f 1\n", + " 11r 0.0000000e+00 1.51e+04 1.09e+05 2.3 2.98e+07 - 1.34e-01 2.58e-03f 1\n", + " 12r 0.0000000e+00 3.92e+04 1.08e+05 2.3 8.59e+07 - 8.37e-03 1.46e-02f 1\n", + " 13r 0.0000000e+00 1.67e+05 1.08e+05 2.3 5.23e+06 - 5.83e-03 9.06e-02f 1\n", + " 14r 0.0000000e+00 4.67e+05 1.05e+05 2.3 1.18e+07 - 2.42e-02 9.08e-02f 1\n", + " 15r 0.0000000e+00 4.64e+05 1.05e+05 2.3 5.75e+06 - 1.97e-03 6.57e-03h 1\n", + " 16r 0.0000000e+00 4.63e+05 9.23e+04 2.3 1.50e+04 -4.0 1.25e-01 1.34e-03h 1\n", + " 17r 0.0000000e+00 6.08e+05 8.46e+04 2.3 5.32e+06 - 8.37e-02 3.04e-01f 1\n", + " 18r 0.0000000e+00 5.71e+05 5.77e+04 2.3 1.87e+06 - 3.20e-01 1.38e-01f 1\n", + " 19r 0.0000000e+00 4.10e+05 5.27e+04 2.3 4.12e+06 - 9.00e-02 3.37e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r 0.0000000e+00 3.86e+05 4.93e+04 2.3 1.63e+04 -3.6 6.50e-02 5.85e-02f 1\n", + " 21r 0.0000000e+00 3.60e+05 4.51e+04 2.3 7.48e+03 -3.1 8.38e-02 6.63e-02h 1\n", + " 22r 0.0000000e+00 3.64e+05 4.08e+04 2.3 4.06e+06 - 9.58e-02 7.04e-02f 1\n", + " 23r 0.0000000e+00 3.86e+05 1.88e+05 2.3 5.59e+06 - 1.68e-01 1.49e-01f 1\n", + " 24r 0.0000000e+00 3.86e+05 1.88e+05 2.3 1.12e+02 4.7 1.81e-03 1.57e-03h 1\n", + " 25r 0.0000000e+00 3.86e+05 1.91e+05 2.3 1.55e+02 4.2 2.71e-03 1.11e-03h 1\n", + " 26r 0.0000000e+00 3.85e+05 1.86e+05 2.3 1.56e+02 3.7 8.21e-04 3.62e-03h 1\n", + " 27r 0.0000000e+00 3.85e+05 3.16e+05 2.3 1.55e+02 5.1 1.83e-02 6.41e-04h 1\n", + " 28r 0.0000000e+00 3.82e+05 3.30e+05 2.3 1.55e+02 4.6 1.40e-02 1.11e-02h 1\n", + " 29r 0.0000000e+00 3.81e+05 7.08e+05 2.3 1.53e+02 5.0 2.85e-02 4.20e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30r 0.0000000e+00 3.72e+05 7.46e+05 2.3 1.53e+02 4.5 4.86e-02 3.45e-02h 1\n", + " 31r 0.0000000e+00 3.67e+05 1.89e+06 2.3 1.47e+02 5.0 1.12e-01 2.04e-02h 1\n", + " 32r 0.0000000e+00 3.24e+05 1.59e+06 2.3 1.44e+02 4.5 1.96e-01 1.79e-01h 1\n", + " 33r 0.0000000e+00 3.23e+05 1.58e+06 2.3 1.19e+02 4.0 4.52e-03 5.61e-03h 1\n", + " 34r 0.0000000e+00 2.94e+05 1.59e+06 2.3 1.18e+02 4.4 3.45e-01 1.47e-01h 1\n", + " 35r 0.0000000e+00 2.80e+05 1.53e+06 2.3 1.01e+02 4.0 1.38e-01 8.76e-02h 1\n", + " 36r 0.0000000e+00 2.52e+05 1.66e+06 2.3 9.17e+01 4.4 3.38e-01 1.83e-01h 1\n", + " 37r 0.0000000e+00 2.39e+05 1.55e+06 2.3 7.50e+01 3.9 9.13e-01 1.05e-01h 1\n", + " 38r 0.0000000e+00 2.13e+05 1.24e+06 2.3 6.72e+01 3.4 5.58e-01 2.28e-01h 1\n", + " 39r 0.0000000e+00 1.95e+05 1.05e+06 2.3 5.18e+01 3.9 1.00e+00 2.15e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40r 0.0000000e+00 1.28e+05 2.34e+05 2.3 4.08e+01 3.4 5.49e-01 1.00e+00h 1\n", + " 41r 0.0000000e+00 1.28e+05 2.87e+05 2.3 8.85e-01 2.9 5.24e-01 9.02e-01f 1\n", + " 42r 0.0000000e+00 1.28e+05 1.76e+05 2.3 3.90e-01 4.2 3.08e-01 9.59e-01f 1\n", + " 43r 0.0000000e+00 1.28e+05 5.03e+04 2.3 1.25e-01 3.8 3.19e-01 1.00e+00f 1\n", + " 44r 0.0000000e+00 1.28e+05 4.94e+04 2.3 4.82e+00 3.3 1.85e-02 1.19e-01f 2\n", + " 45r 0.0000000e+00 1.28e+05 1.37e+04 2.3 3.62e-01 3.7 8.33e-01 1.00e+00f 1\n", + " 46r 0.0000000e+00 1.28e+05 7.07e+03 1.6 5.21e-01 3.2 8.97e-01 1.00e+00f 1\n", + " 47r 0.0000000e+00 1.29e+05 5.44e+02 1.6 9.53e-01 2.8 8.34e-01 8.12e-01f 1\n", + " 48r 0.0000000e+00 1.29e+05 8.91e+02 0.9 2.85e+00 2.3 4.12e-01 2.43e-01f 1\n", + " 49r 0.0000000e+00 1.30e+05 6.99e+02 0.9 8.46e+00 1.8 7.74e-01 2.05e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50r 0.0000000e+00 1.31e+05 3.95e+04 0.9 2.41e+01 1.3 1.00e+00 1.51e-01f 1\n", + " 51r 0.0000000e+00 1.30e+05 4.66e+04 0.9 7.23e+01 0.8 1.00e+00 5.24e-02f 1\n", + " 52r 0.0000000e+00 1.18e+05 3.45e+04 0.9 2.17e+02 0.4 6.96e-01 1.67e-01f 1\n", + " 53r 0.0000000e+00 1.17e+05 1.74e+04 0.9 6.50e+02 -0.1 1.43e-01 1.50e-02f 1\n", + " 54r 0.0000000e+00 1.17e+05 4.23e+04 0.9 1.94e+03 -0.6 6.50e-01 3.25e-02f 1\n", + " 55r 0.0000000e+00 1.18e+05 5.54e+04 0.9 3.69e+03 -1.1 4.70e-01 9.48e-03f 1\n", + " 56r 0.0000000e+00 1.25e+05 2.75e+04 0.9 1.01e+02 -1.5 7.89e-01 1.78e-01f 1\n", + " 57r 0.0000000e+00 1.28e+05 2.68e+04 0.9 9.57e+01 -2.0 9.34e-01 1.60e-01f 1\n", + " 58r 0.0000000e+00 1.37e+05 5.37e+02 0.9 2.51e+02 -2.5 1.00e+00 6.23e-01f 1\n", + " 59r 0.0000000e+00 1.40e+05 1.78e+04 0.2 7.53e+02 -3.0 4.51e-01 6.22e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60r 0.0000000e+00 1.40e+05 1.99e+03 0.2 2.25e+03 -3.4 6.57e-01 3.90e-01f 1\n", + " 61r 0.0000000e+00 1.40e+05 6.25e+04 0.2 8.45e+02 -3.0 1.00e+00 2.93e-01f 1\n", + " 62r 0.0000000e+00 1.40e+05 4.84e+04 0.2 2.48e+03 -3.5 1.00e+00 2.59e-01f 1\n", + " 63r 0.0000000e+00 1.40e+05 9.09e+04 0.2 8.10e+02 -4.0 5.18e-01 4.12e-02f 1\n", + " 64r 0.0000000e+00 1.40e+05 4.52e+03 0.2 3.19e+02 -3.6 5.90e-01 8.39e-01f 1\n", + " 65r 0.0000000e+00 1.40e+05 9.20e+03 0.2 8.45e+02 -4.0 2.58e-01 3.11e-01f 1\n", + " 66r 0.0000000e+00 1.40e+05 9.35e+02 0.2 2.32e+03 -4.5 9.50e-02 5.05e-01f 1\n", + " 67r 0.0000000e+00 1.40e+05 1.80e+03 0.2 3.94e+03 -5.0 1.00e+00 6.61e-02f 1\n", + " 68r 0.0000000e+00 1.40e+05 2.93e+03 0.2 4.85e+03 -5.5 9.99e-01 2.84e-01f 1\n", + " 69r 0.0000000e+00 1.38e+05 6.05e+03 0.2 6.81e+03 -5.9 1.00e+00 2.40e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70r 0.0000000e+00 1.37e+05 1.78e+03 0.2 2.85e+03 -5.5 1.00e+00 1.00e+00f 1\n", + " 71r 0.0000000e+00 1.34e+05 1.31e+03 0.2 8.14e+03 -6.0 3.19e-01 3.05e-01f 1\n", + " 72r 0.0000000e+00 1.31e+05 1.83e+03 0.2 2.65e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 73r 0.0000000e+00 1.28e+05 3.42e+03 0.2 1.45e+04 -6.0 1.00e+00 2.70e-01f 1\n", + " 74r 0.0000000e+00 1.24e+05 1.09e+01 0.2 4.06e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 75r 0.0000000e+00 1.05e+05 7.56e+03 -0.5 5.64e+04 -6.1 2.15e-01 3.59e-01f 1\n", + " 76r 0.0000000e+00 1.05e+05 1.79e+04 -0.5 2.46e+03 -4.8 5.42e-01 1.26e-01f 1\n", + " 77r 0.0000000e+00 1.05e+05 2.30e+04 -0.5 9.93e+03 -5.2 1.04e-02 6.09e-02f 1\n", + " 78r 0.0000000e+00 1.05e+05 1.44e+03 -0.5 2.90e+03 -4.8 1.16e-01 1.32e-02f 1\n", + " 79r 0.0000000e+00 1.04e+05 8.21e+04 -0.5 9.44e+03 -5.3 4.02e-02 1.19e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80r 0.0000000e+00 1.04e+05 4.46e+03 -0.5 1.93e+03 -4.9 2.08e-01 2.98e-02f 1\n", + " 81r 0.0000000e+00 9.40e+04 1.37e+05 -0.5 1.15e+04 -5.3 5.49e-03 2.67e-01f 1\n", + " 82r 0.0000000e+00 9.39e+04 1.21e+05 -0.5 2.56e+03 -4.9 3.04e-01 9.74e-03f 1\n", + " 83r 0.0000000e+00 9.25e+04 1.08e+05 -0.5 4.97e+03 -5.4 1.59e-01 1.20e-01f 1\n", + " 84r 0.0000000e+00 9.25e+04 1.35e+05 -0.5 8.51e+03 -5.9 5.44e-01 3.08e-02f 1\n", + " 85r 0.0000000e+00 1.04e+05 1.06e+05 -0.5 1.26e+04 -6.3 1.73e-01 4.10e-01f 1\n", + " 86r 0.0000000e+00 1.08e+05 1.45e+05 -0.5 2.50e+04 -6.8 1.23e-01 7.63e-02f 1\n", + " 87r 0.0000000e+00 1.07e+05 1.40e+05 -0.5 4.68e+02 -2.8 3.12e-02 1.16e-01h 1\n", + " 88r 0.0000000e+00 1.07e+05 1.34e+05 -0.5 1.25e+02 -2.4 1.37e-01 6.14e-02h 1\n", + " 89r 0.0000000e+00 1.05e+05 1.21e+05 -0.5 6.38e+01 -1.9 4.82e-02 1.54e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r 0.0000000e+00 1.04e+05 1.11e+05 -0.5 2.62e+01 -1.5 9.28e-02 1.14e-01h 1\n", + " 91r 0.0000000e+00 1.02e+05 8.74e+04 -0.5 2.58e+01 -2.0 1.72e-01 2.50e-01h 1\n", + " 92r 0.0000000e+00 1.02e+05 7.56e+04 -0.5 2.13e+01 -1.6 3.40e-01 1.09e-01f 1\n", + " 93r 0.0000000e+00 1.02e+05 5.81e+04 -0.5 9.06e+00 -2.0 6.37e-01 2.34e-01h 1\n", + " 94r 0.0000000e+00 1.02e+05 3.30e+04 -0.5 2.09e+01 -2.5 1.00e+00 4.49e-01h 1\n", + " 95r 0.0000000e+00 1.01e+05 2.02e+03 -0.5 9.58e+01 -3.0 4.65e-01 8.13e-01f 1\n", + " 96r 0.0000000e+00 1.02e+05 1.56e+04 -0.5 8.77e+01 -3.5 7.24e-01 1.53e-01f 1\n", + " 97r 0.0000000e+00 1.02e+05 5.99e+03 -0.5 2.31e+02 -3.9 3.97e-01 4.89e-01f 1\n", + " 98r 0.0000000e+00 1.04e+05 4.62e+03 -0.5 4.75e+02 -4.4 6.42e-01 1.95e-01f 1\n", + " 99r 0.0000000e+00 1.04e+05 9.76e+02 -0.5 8.15e+02 -4.9 7.06e-01 6.61e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r 0.0000000e+00 1.05e+05 7.45e+03 -0.5 2.44e+03 -5.4 1.00e+00 1.91e-01f 1\n", + " 101r 0.0000000e+00 1.06e+05 1.94e+03 -0.5 7.23e+02 -4.9 1.00e+00 3.62e-01f 1\n", + " 102r 0.0000000e+00 1.07e+05 7.40e+03 -0.5 1.49e+03 -5.4 1.00e+00 4.66e-01f 1\n", + " 103r 0.0000000e+00 1.08e+05 3.03e+03 -0.5 1.66e+03 -5.9 8.96e-01 8.34e-01f 1\n", + " 104r 0.0000000e+00 1.10e+05 5.48e+02 -0.5 9.38e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 105r 0.0000000e+00 1.10e+05 1.76e+02 -0.5 1.46e+03 -6.0 7.45e-01 1.00e+00f 1\n", + " 106r 0.0000000e+00 1.10e+05 7.27e+01 -0.5 6.32e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 107r 0.0000000e+00 1.11e+05 1.41e+03 -0.5 1.49e+03 -6.0 1.00e+00 9.82e-01f 1\n", + " 108r 0.0000000e+00 1.12e+05 1.04e+03 -0.5 3.05e+03 -6.5 1.00e+00 4.21e-01f 1\n", + " 109r 0.0000000e+00 1.12e+05 3.92e+02 -0.5 7.12e+03 -7.0 8.81e-01 5.45e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110r 0.0000000e+00 1.12e+05 6.27e+02 -0.5 1.40e+04 -7.4 1.00e+00 2.04e-01f 1\n", + " 111r 0.0000000e+00 1.27e+05 1.93e+02 -0.5 2.11e+04 -7.9 7.01e-01 6.92e-01f 1\n", + " 112r 0.0000000e+00 1.51e+05 1.49e+02 -0.5 2.24e+04 -8.4 4.24e-01 4.78e-01f 1\n", + " 113r 0.0000000e+00 1.28e+05 1.63e+01 -0.5 2.40e+04 -8.9 1.00e+00 1.00e+00f 1\n", + " 114r 0.0000000e+00 1.36e+05 3.29e+02 -0.5 4.21e+04 -9.3 6.45e-01 1.00e+00f 1\n", + " 115r 0.0000000e+00 5.01e+05 1.31e+03 -0.5 9.66e+04 -9.8 9.22e-01 1.00e+00h 1\n", + " 116r 0.0000000e+00 8.78e+05 4.66e+02 -0.5 2.96e+05 -10.3 9.46e-01 1.00e+00h 1\n", + " 117r 0.0000000e+00 6.70e+04 4.18e+02 -0.5 9.60e+05 -10.8 1.00e+00 1.00e+00h 1\n", + " 118r 0.0000000e+00 5.21e+04 9.75e+02 -0.5 3.82e+06 -11.3 1.00e+00 7.10e-01f 1\n", + " 119r 0.0000000e+00 5.30e+04 9.97e+02 -0.5 9.41e+06 - 8.43e-02 2.44e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120r 0.0000000e+00 5.40e+04 9.62e+02 -0.5 2.95e+06 - 1.00e+00 1.41e-01f 1\n", + " 121r 0.0000000e+00 5.13e+04 5.63e+01 -0.5 1.96e+05 - 1.00e+00 1.00e+00f 1\n", + " 122r 0.0000000e+00 5.06e+04 7.06e-01 -0.5 1.45e+04 - 1.00e+00 1.00e+00h 1\n", + " 123r 0.0000000e+00 4.48e+04 1.60e+01 -2.9 1.41e+04 - 8.33e-01 7.83e-01f 1\n", + " 124r 0.0000000e+00 7.43e+04 1.23e+02 -2.9 1.09e+05 -9.9 1.51e-01 1.14e-01f 1\n", + " 125r 0.0000000e+00 7.21e+04 3.54e+02 -2.9 1.66e+05 - 1.51e-01 3.48e-02h 1\n", + " 126r 0.0000000e+00 4.03e+04 3.48e+02 -2.9 6.43e+04 - 4.59e-01 5.71e-01f 1\n", + " 127r 0.0000000e+00 9.43e+03 9.62e+01 -2.9 2.75e+04 - 5.72e-01 8.74e-01h 1\n", + " 128r 0.0000000e+00 7.66e+03 2.89e+02 -2.9 4.00e+03 - 7.38e-01 1.00e+00h 1\n", + " 129r 0.0000000e+00 8.78e+02 2.90e+01 -2.9 1.50e+03 - 9.18e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 130r 0.0000000e+00 7.37e+02 1.27e+01 -2.9 1.32e+03 - 1.00e+00 1.00e+00h 1\n", + " 131r 0.0000000e+00 3.66e+02 6.41e+00 -2.9 9.22e+02 - 1.00e+00 1.00e+00h 1\n", + " 132r 0.0000000e+00 8.13e+00 2.77e-02 -2.9 6.19e+01 - 1.00e+00 1.00e+00h 1\n", + " 133r 0.0000000e+00 7.03e+03 1.41e+01 -4.3 5.16e+03 - 7.78e-01 7.77e-01f 1\n", + " 134r 0.0000000e+00 5.08e+03 4.30e+02 -4.3 3.71e+03 - 1.00e+00 7.18e-01h 1\n", + " 135r 0.0000000e+00 2.02e+02 2.79e+01 -4.3 6.26e+02 - 1.00e+00 1.00e+00h 1\n", + " 136r 0.0000000e+00 1.50e+01 2.52e+00 -4.3 1.46e+02 - 1.00e+00 1.00e+00h 1\n", + " 137r 0.0000000e+00 8.83e-01 1.86e-02 -4.3 1.27e+01 - 1.00e+00 1.00e+00h 1\n", + " 138r 0.0000000e+00 7.60e-01 3.09e-05 -4.3 1.51e+00 - 1.00e+00 1.00e+00h 1\n", + " 139 0.0000000e+00 7.60e-01 1.08e+06 -1.0 8.24e+02 - 9.89e-01 7.57e-06h 17\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 140 0.0000000e+00 7.60e-01 1.94e+06 -1.0 8.24e+02 - 9.90e-01 1.89e-06h 19\n", + " 141 0.0000000e+00 2.27e+02 9.80e+05 -1.0 8.24e+02 - 4.96e-01 4.96e-01s 21\n", + " 142r 0.0000000e+00 2.27e+02 1.00e+03 -1.0 0.00e+00 - 0.00e+00 0.00e+00R 1\n", + " 143r 0.0000000e+00 2.20e+02 1.07e+04 -1.0 2.63e+04 - 2.05e-01 5.61e-03f 1\n", + " 144r 0.0000000e+00 2.03e+03 1.87e+03 -1.0 2.78e+04 - 9.30e-01 2.21e-01f 1\n", + " 145r 0.0000000e+00 1.09e+04 2.99e+03 -1.0 1.86e+04 - 3.04e-01 6.48e-01f 1\n", + " 146r 0.0000000e+00 1.30e+04 1.58e+03 -1.0 1.46e+05 - 2.04e-01 3.61e-01f 1\n", + " 147r 0.0000000e+00 1.36e+04 3.08e+02 -1.0 1.18e+04 - 9.12e-01 1.00e+00f 1\n", + " 148r 0.0000000e+00 1.10e+04 2.16e+00 -1.0 4.09e+00 -4.0 1.00e+00 1.00e+00h 1\n", + " 149r 0.0000000e+00 1.22e+04 1.65e+00 -1.7 2.94e+01 -4.5 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 150r 0.0000000e+00 1.31e+04 1.64e+00 -1.7 5.03e+01 -5.0 1.00e+00 1.00e+00f 1\n", + " 151r 0.0000000e+00 1.29e+04 3.23e+00 -1.7 3.50e+01 -5.4 1.00e+00 1.00e+00h 1\n", + " 152r 0.0000000e+00 1.19e+04 5.44e+02 -1.7 3.69e+04 - 1.00e+00 6.74e-01f 1\n", + " 153r 0.0000000e+00 3.43e+03 2.19e+01 -1.7 1.23e+04 - 1.00e+00 1.00e+00h 1\n", + " 154r 0.0000000e+00 2.96e+03 5.24e-01 -1.7 1.78e+03 - 1.00e+00 1.00e+00h 1\n", + " 155r 0.0000000e+00 2.99e+03 2.57e+01 -2.5 1.05e+04 - 8.24e-01 8.54e-01f 1\n", + " 156r 0.0000000e+00 4.83e+03 2.10e+01 -2.5 3.56e+03 - 1.00e+00 9.28e-01h 1\n", + " 157r 0.0000000e+00 1.91e+02 6.11e+00 -2.5 7.38e+02 - 1.00e+00 1.00e+00h 1\n", + " 158r 0.0000000e+00 6.34e+01 3.88e-02 -2.5 7.32e+01 - 1.00e+00 1.00e+00h 1\n", + " 159r 0.0000000e+00 1.16e+04 1.91e+02 -3.8 5.52e+03 - 7.33e-01 9.36e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 160r 0.0000000e+00 8.60e+03 5.01e+02 -3.8 4.56e+03 - 3.35e-01 3.58e-01h 1\n", + " 161r 0.0000000e+00 4.61e+03 2.92e+03 -3.8 2.07e+03 - 8.26e-01 5.26e-01h 1\n", + " 162r 0.0000000e+00 3.60e+02 8.99e+03 -3.8 8.68e+02 - 5.05e-01 1.00e+00h 1\n", + " 163r 0.0000000e+00 1.13e+02 3.07e+02 -3.8 5.08e+02 - 1.00e+00 1.00e+00h 1\n", + " 164r 0.0000000e+00 1.67e+02 3.30e+01 -3.8 6.12e+02 - 1.00e+00 1.00e+00h 1\n", + " 165r 0.0000000e+00 1.22e+01 1.46e-01 -3.8 1.59e+02 - 1.00e+00 1.00e+00h 1\n", + " 166r 0.0000000e+00 2.15e+00 1.25e-03 -3.8 1.80e+01 - 1.00e+00 1.00e+00h 1\n", + " 167r 0.0000000e+00 6.62e+02 3.07e+02 -5.7 2.03e+03 - 9.26e-01 5.74e-01f 1\n", + " 168r 0.0000000e+00 4.94e+02 1.08e+02 -5.7 1.15e+03 - 1.00e+00 7.82e-01h 1\n", + " 169r 0.0000000e+00 4.16e+02 2.06e+02 -5.7 6.08e+02 - 9.82e-01 1.68e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 170r 0.0000000e+00 3.63e+02 1.05e+04 -5.7 1.90e+02 - 1.00e+00 9.40e-01h 1\n", + " 171r 0.0000000e+00 4.94e+03 1.45e+05 -5.7 6.81e+00 - 1.00e+00 9.80e-02h 1\n", + " 172r 0.0000000e+00 5.01e+03 1.47e+05 -5.7 3.34e-01 - 1.00e+00 1.00e+00f 1\n", + " 173r 0.0000000e+00 3.29e+03 2.38e+05 -5.7 4.37e-01 - 1.00e+00 1.00e+00H 1\n", + " 174r 0.0000000e+00 1.30e+03 9.35e+04 -5.7 5.77e-01 - 1.00e+00 2.87e-01h 2\n", + " 175r 0.0000000e+00 2.20e+02 1.60e+04 -5.7 9.32e-02 - 1.00e+00 1.00e+00h 1\n", + " 176r 0.0000000e+00 2.98e+01 2.17e+03 -5.7 3.88e-02 - 9.67e-01 1.00e+00h 1\n", + " 177 0.0000000e+00 2.58e+01 8.80e+06 -1.0 4.77e-01 - 9.90e-01 1.00e+00f 1\n", + " 178 0.0000000e+00 5.64e+00 1.91e+06 -1.0 9.74e-02 - 9.90e-01 1.00e+00h 1\n", + " 179 0.0000000e+00 2.20e-04 3.75e+03 -1.0 5.06e-06 - 9.92e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 180 0.0000000e+00 7.45e-09 1.06e-02 -2.5 1.31e-07 - 1.00e+00 1.00e+00h 1\n", + " 181 0.0000000e+00 2.24e-08 2.57e-04 -7.0 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 182 0.0000000e+00 2.24e-08 3.90e-11 -7.0 9.85e-08 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 182\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 3.8958489431350689e-11 3.8958489431350689e-11\n", + "Constraint violation....: 2.9103830456733704e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593320084580268e-14 2.8593320084580268e-14\n", + "Complementarity.........: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "Overall NLP error.......: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 253\n", + "Number of objective gradient evaluations = 22\n", + "Number of equality constraint evaluations = 253\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 185\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 182\n", + "Total seconds in IPOPT = 0.150\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Check physical units consistency, solve and check solver status\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.util.check_units import assert_units_consistent\n", + "\n", + "assert_units_consistent(m)\n", + "results = solver.solve(m, tee=True, symbolic_solver_labels=True)\n", + "assert results.solver.termination_condition == TerminationCondition.optimal" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.R101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For comparison, we will call and build the HDA flowsheet replacing the second `Flash` with a `TrayColumn` distillation unit model. The flowsheet costing occurs in the external script `hda_flowsheets_for_costing_notebook.py` and is not shown here:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'fs.R101.control_volume.scaling_factor'\n", - "that contains 2 component keys that are not exported as part of the NL file.\n", - "Skipping.\n" - ] + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Solving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Adding distillation column and resolving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 17\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Complete.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n" + ] + } + ], + "source": [ + "from pyomo.common.log import LoggingIntercept\n", + "import logging\n", + "from io import StringIO\n", + "\n", + "stream = StringIO()\n", + "with LoggingIntercept(stream, \"idaes\", logging.WARNING):\n", + " # Source file for prebuilt flowsheets\n", + " from hda_flowsheets_for_costing_notebook import hda_with_distillation\n", + "\n", + " # Build hda model with distillation column and return model object\n", + " n = hda_with_distillation(tee=False)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H101.control_volume.properties_out[0.0].scaling_factor' that contains 26\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Results Comparison and Visualization\n", + "For the two flowsheets above, let's sum the total operating and capital costs of each scenario. We will display overall process economics results and compare the two flowsheets:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix\n", - "'fs.H101.control_volume.properties_in[0.0].scaling_factor' that contains 25\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - } - ], - "source": [ - "from pyomo.common.log import LoggingIntercept\n", - "import logging\n", - "from io import StringIO\n", - "\n", - "stream = StringIO()\n", - "with LoggingIntercept(stream, \"idaes\", logging.WARNING):\n", - " # Source file for prebuilt flowsheets\n", - " from hda_flowsheets_for_costing_notebook import hda_with_distillation\n", - "\n", - " # Build hda model with distillation column and return model object\n", - " n = hda_with_distillation(tee=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results Comparison and Visualization\n", - "For the two flowsheets above, let's sum the total operating and capital costs of each scenario. We will display overall process economics results and compare the two flowsheets:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports and data gathering\n", - "from matplotlib import pyplot as plt\n", - "\n", - "plt.style.use(\"dark_background\") # if using browser in dark mode, uncomment this line\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "# Automatically get units that we costed - this will exclude C101 for both flowsheets\n", - "\n", - "two_flash_unitlist = [\n", - " getattr(m.fs, unit) for unit in dir(m.fs) if hasattr(getattr(m.fs, unit), \"costing\")\n", - "]\n", - "distillation_unitlist = [\n", - " getattr(n.fs, unit) for unit in dir(n.fs) if hasattr(getattr(n.fs, unit), \"costing\")\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Costs in $1000:\n" - ] + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Imports and data gathering\n", + "from matplotlib import pyplot as plt\n", + "\n", + "plt.style.use(\"dark_background\") # if using browser in dark mode, uncomment this line\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "# Automatically get units that we costed - this will exclude C101 for both flowsheets\n", + "\n", + "two_flash_unitlist = [\n", + " getattr(m.fs, unit) for unit in dir(m.fs) if hasattr(getattr(m.fs, unit), \"costing\")\n", + "]\n", + "distillation_unitlist = [\n", + " getattr(n.fs, unit) for unit in dir(n.fs) if hasattr(getattr(n.fs, unit), \"costing\")\n", + "]" + ] }, { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Equipmentfs.H101fs.R101fs.F101fs.F102fs.D101fs.H102
Distillation13.28333413.5522947.7813320.0000007.607433.32944
Two Flash13.28333410.7558787.7813327.7813320.000000.00000
\n", - "
" + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Equipmentfs.H101fs.R101fs.F101fs.F102fs.D101fs.H102
Distillation13.28333413.5522947.7813320.0000007.607433.32944
Two Flash13.28333410.7558787.7813327.7813320.000000.00000
\n", + "
" + ], + "text/plain": [ + "Equipment fs.H101 fs.R101 fs.F101 fs.F102 fs.D101 fs.H102\n", + "Distillation 13.283334 13.552294 7.781332 0.000000 7.60743 3.32944\n", + "Two Flash 13.283334 10.755878 7.781332 7.781332 0.00000 0.00000" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjMAAAHvCAYAAAChRl4LAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAARHlJREFUeJzt3QeYU9X2+P01Qy9DR3qTXkRRUHpHkXJBUBTFK1IuotIuSBUFEQGRpniBq1gu0pFepBdpUkWQ3rsDwlCHnv+z9u9N3kxPpiV75vt5nvMwOTk52XNIMit7r712gIg4BAAAwFKBvm4AAABAXBDMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAEg0lStXlunTp0u+fPmSbVttugaALQKoAAzETp48eWT06NEyd+5cmT17doT7a9euLZ06dZJhw4bJH3/8EeYxTg8ePJDr16/LyZMnZcuWLbJx48Zon7NOnTryr3/9Sw4dOiSDBg2KsY36B/OLL77w6PfR43bu3Bnl/TVr1pTOnTvLv//9b7lw4YLExquvviozZsyQcuXKyZ9//unRYypVqiQvvPCCFCpUSB49eiSnTp2SrVu3ypo1a2LVhri0Nblcg/j4PYHERM8MEEuZMmWS1157TcqXLx/p/UWLFjX3awAT/jGpU6eW+fPny5IlS2Tv3r3y+OOPy4IFC0yQUqNGjSifs0+fPvLyyy/LgAEDJG/evDG28caNG+Z53LdnnnlGGjZsGGF/TH+0ihQpYtquv0NiyJ49u7k+GzZskMKFC8u2bdvkt99+MwHavHnzzLVKSJs3bza/75kzZ5LdNUjs3xOID7o2ExvXgNeAl6+BkiVLOtSQIUMivb99+/bm/hdeeMGjx2TJksWxbt06x+3btx0VK1aMcH/BggUdDx48cPTr189x69Ytx4ABA2L1f7ZlyxbHhQsXvH7cW2+9Zdquv0Ns3y+vvvqqOUfZsmWjPS516tSO7du3Oy5evOgoXbp0hPvz5cvn2Lp1a6K/ZpPLNYiP35ONayCJeA1Sxks4BCDOQkJCpHXr1nLixAn5/PPPpW7dumHub9++vdy6dUu+/PJLKV68uLk9dOjQeLnygYGB0rJlS6lVq5ZkyJBBjh07Jj/99JMZ/lJ6nw47qFGjRpkeH/ehqdKlS8tHH31k9jkcDgkNDZWDBw/KtGnT5Ny5c163p2PHjlKxYkV5/fXX5cCBAxHu13M+//zzrtuePn+9evWkQ4cO0qVLF9Mb9sYbb5jfd926deZYHcJxz23p1q2b9OrVy5zD36+BJ/+PTlWqVJGmTZtK7ty5zXl++eUX2bRpk7kvpt8zpscDvsAwE+BHdKhH/7BqzkKWLFnC/JF6++23ZcqUKSagmTBhghkKaNCgQZyfM23atCb34ttvv5UrV66YYQzN99m/f7/5g6X0j/KuXbvMz6tXr44wNHX58mXXPh0u2717t3msnqNUqVJet0mHODQYiCwXyUlzjZw8ff5ixYqZc7dp08bkHGmQcPHiRZk0aZJ5XECAphH+H81P0WOd/w/+fg08+X9UmgejrzEd6ly/fr3cvHlTPv30UzOE6cnvGdPjAV+hO5BrwGsgFq8B55DRvn37HNOnT4+w/fbbb14NMzm3sWPHmmOeeeYZ175GjRqZfWXKlHHt27Ztm2PmzJlxHmb65JNPzLmrVavm2hcQEOBYsWKF4+rVq47MmTPHaughMDDQsWPHDsfcuXO9HmLR5/3999/j9LqM7Pk7depknn/+/Pnmd3Tub9y4sdn/r3/9K9q2+vM18PT/8eTJk44JEyZEeHzevHk9+j09eTwb10AS+RowzATEkSZh6jfXyGYePfvss16fT7+Nq/Tp04cZctBvwfot20l7Z3TLkSOH6RWILR3a0m/x7sMEOkwyZswYWbp0qTRu3NgMlcSkQIECZqZOyZIlzRCH9nJkzZo1TA+Tp/TxzuvgKW+ef/LkyeZ3dNIk2yNHjpjekP/+979etzc2bYjva+Dp/+O9e/fM7ChNTHdP+j5//rxHzxPXxwMJgWAGiCMNMGbOnBlhf8aMGc3UbG9ly5bN/KtDBSpXrlzmD5E+j9YncUqXLp2kSZNG3nrrLZPbEFs6S0anhYfnnCmjw1kx0VyURYsWmfPov8HBwfLw4UOTU6FTkL2lwZnO5PGUt89/9OjRSPeVKVPG67bGtg3xfQ08/X/s3r27Ga7UWVo7duwwQbIG45E9NjJxfTyQEAhmAD+jvTmadKm5C0pzZTTJUuvVhKcBjyYCxyWYuX//vsm3CM/ZM6TfxGPy2WefmfZqDo97Em3btm1j1Sb9w9i8eXOPe528fX4NBCPb58nvGl9tiO9r4On/o/bS5M+f3/QcVq9eXV588UXp3bu36cHRfJiYxPXxQEIgARjwIzoL5amnnpKpU6eab/VKg5XFixeb3p/w27hx48wsGv2jElt79uwxtWfck1+Vc4js999/dxX4cyYjRza8sm/fvjB/xPWPqM7GiQ0dPtPn0V6AqLgP4Xn7/Pr7utMeLu090aTd6PjzNfD0/1Hp8JUGJf3795cKFSrIrFmz5P333zdJvTH9np48HkhsBDOAn2jSpIn5o6DDSfpHQun0bJ2Bo1NfI6N/wDRXQXNqYksDIp2m/MEHH7j26TdvLcynlYtXrVpl9p09e9b8W7BgwUjboTOwgoKCzG39g6pTeXW6eWzoc44dO9bMkOnatWuYP6p67jfffFNWrFgR6+d/5ZVXwhQd/Pjjj83w3vjx46Ntlz9fA0/+H1OmTGmmXYfvwdFgTmdGOYOYqH5PTx8P+AKZ51wDXgOJXDTPOQNqxowZjmXLljnOnTvnCA4OdowYMcKRMWNG1/HTpk1z3Llzx5E+ffoo2zF58mRTRM85WyU2RfN69+5tivXt2bPH8csvvzhCQkLMbKxChQq5jkmRIoWZQaXt/Pnnn037nTOutKjbiRMnHOfPn3csXLjQcfjwYcfAgQMd33zzjePSpUtez+Rxbjq76MyZM6a9ixcvdixYsMBx+vRp04aRI0e6jvP0+Z2zmerVq+fYvXu3ufZ79+51hIaGOt57770wzx1ZW/35Gnjy/6izm7766ivzetu4caOZZXXw4EHHqVOnwrxOo/o9PX08G9dAEvkasDYTEEua4KuJubq+jg4vhKcJl9rFrzU5/vrrrzCPcdJvspofo0XNdDaN+wwb1axZM7lz544sX748ynZoz40OL2giptZM8SRRVWfKLFy4MMz+zJkzm/bqfcePH3etJ+UuRYoU8txzz5leDf35119/dc1i0W/rOstFz6PDNZrno0Ms2jvgnO2lQzFVq1aVZcuWhamREpMnnnjCJLjq9Tp9+rQcPnzY5Ii48+T5NSF74sSJ5lzabl06QoeCdBbQpUuXwpwvqrb68zXw9P9R79NlOHLmzGnarnVl3IfHYvo9PXk8kJgIZgAkG+7BjC7WCCBpIGcGAABYjWAGAABYjWEmAMmGzvbRnBYtanf79m1fNwdAPCGYAQAAVmOYCQAAWI1gBgAAWC3ZrM2ktRK0ngcAALCHVtWOaVX2lMklkNHiVQAAwD758uWLNqBJFsGMs0dGLwa9MwAA2NMro50RMf3tThbBjJNeDIIZAACSFhKAAQCA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1QhmAACA1VL6ugFIWA8Xt+MSJyMpmnzn6yYAQKKjZwYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFgtpa8bgIT16cPuXOJk5TtfNwAAEh09MwAAwGoEMwAAwGoEMwAAwGoEMwAAwGoEMwAAwGoEMwAAwGoEMwAAwGoEMwAAwGoEMwAAwGoEMwAAwGoEMwAAwGp+szbTU089Ja+++qps3LhRlixZEua+bNmySatWrSRXrlyyd+9emTdvnjgcDp+1FQAA+A+/6JnJlCmTzJo1S9555x2pX79+mPsKFy5sAhgNdDJkyCCjRo2SRYsWSUBAgM/aCwAA/IdfBDP//e9/Zfr06XLy5MkI940YMcLsr1evnvTu3Vvq1q0rzz//vAluAAAAfB7MdOjQwfS+fPLJJxHuS5EihTRt2lR++uknefTokdl34sQJWb9+vbRo0cIHrQUAAP7GpzkzpUuXlqFDh0rVqlXl4cOHEe4vWLCgpEuXTo4ePRpmv96uUqVKlOdNnTq1pEmTxnU7KCgonlsOAAAkuffMpE2bVmbOnCn9+vWTY8eORXqM5sio69evh9l/7do1132R0XPqY5zbuXPn4rn1AABAknsw06ZNGylQoIAUL15chg0bZrY8efJItWrVzM+a4Hvz5k1zbObMmcM8NkuWLK77IqOP16Ri55YvX74E/30AAEAyG2bauXOnDB8+PMw+HWq6e/euhISEmKnXp0+fNkFLyZIlZcWKFa7j9PaBAweiPPe9e/fMBgAAkj6fBTO7d+82m7vXXntNduzYYWYwKU361Zoy//znP2XixIly//59k2dTvXp1U3cGAJKze4N7+boJSESpP/6C6+2vs5li0rdvX1M0b8uWLTJp0iRZs2aNzJkzxwQ5AAAAflMBWI0bN84MLbk7f/68lC9fXv7xj3+YCsBaXG/16tU+ayMAAPAvfhXM/PDDD5Huv3XrlimqBwAAYN0wEwAAQHQIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNVS+roBSFg106fhEgMAkjR6ZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNVS+roBAIDY2VS1I5cuWfnC1w3wW/TMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAAAAqxHMAAAAq/m8aF5AQICULFlSMmbMKEePHpWQkJBIjytWrJjkypVLDh48KH///XeitxMAAPgnn/bMtGzZUg4dOiQzZsyQiRMnyrlz52TEiBFhjkmXLp0sWbJEduzYIV999ZWcOXNGevbs6bM2AwAA/+LTnhntjalRo4b89ddf5nbVqlVl06ZNsnr1almxYoXZN3jwYClbtqwUL15cLl26JC+++KIsXbpUNm/eLFu2bPFl8wEAQHLvmfnxxx9dgYzavn273L9/3wwnOb311lvy7bffmkBGLVu2THbv3i1t27b1SZsBAIB/8XnOTLZs2aRChQqSKVMmefvtt2Xbtm0yZ84cc1/evHnlsccek127doV5jN5+6qmnojxn6tSpJU2aNK7bQUFBCfgbAACAZB3MFClSRPr27Ss5cuSQAgUKyIABAyQ0NNTclzVrVvPvlStXwjxGE4Cd90WmX79+MmjQoARuOQAA8Ac+D2Z27twpDRo0MD9XrlxZ1qxZIzdv3pSpU6fKvXv3XEnA7tKnT++6LzLDhg2T0aNHh+mZ0eRiAACQ9PhVnZmtW7eavBlncKMzlx4+fCj58+cPc5zePnnyZJTn0UDnxo0bYTYAAJA0+SyYCQwMND0s4XNddNgpODjY3L5z5478+uuv0rx58zAzoOrVq+ea7QQAAJI3nw0zpUqVyvTC/O9//5P9+/dLlixZpEOHDpIyZUpTT8apf//+snbtWjNspFOx33vvPTNkpDOcAAAAfNYzc/fuXalVq5bpjdFZTM8//7wsWLBASpUqZYaXnDSAqVatmmTOnNlM09bb1atXl9u3b/O/BwAAfJsAfPnyZRkyZIhHScLt27dPlDYBAAC7+FUCMAAAgLcIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNUIZgAAgNVS+roBSFi16h/mEgMAkjSve2aeffZZmTZtmpw8eVJCQ0Plzp075mfdV6lSpYRpJQAAQHz0zDRr1kxmz54t27dvlylTpsilS5fE4XDIY489JvXq1ZNNmzbJK6+8IgsWLPDmtAAAAIkTzHz22WfSs2dP+eqrryLcN3DgQOnSpYsMHTqUYAYAAPjnMFPRokVNj0xU9L5ixYrFR7sAAADiP5g5deqUNG/ePMr79T7NnwEAAPDLYabBgwfLDz/8IC1atJC1a9eanBmVM2dOqV27trz44ovStm3bhGorAABA3IIZnbEUHBxs8mY+/vhjyZw5s9l/7do12bJlizRq1EhWrVrlzSkBAAASt86MBivOgCVdunTmX52iDQAAYF3RPIIYAADgaxTNAwAAVqNoHgAAsBpF8wAAgNUomgcAAKxG0TwAAGA1iuYBAACrUTQPAABYjaJ5AADAahTNAwAAVqNoHgAAsBpF8wAAgNUomgcAAKwWICIOTw++c+eO5M6dW0JCQiK9P0uWLHLx4kVJmzat+JOgoCC5fv26ZMqUSW7cuCHJySPHIl83AYkoMKAp1zsZ4f2dvCTH93eQh3+/KZoHAACsRtE8AABgNYrmAQAAq1E0DwAAWI2ieQAAIHkVzYvJ999/H9+nBAAASLxgpm3btvF9SgAAgPgZZnrrrbe8ORwAAMC/gpkffvhBHjx4kHCtAQAASMhhpp07d0qVKlUkVapUUW4AAAB+G8xMmDBB3nnnnYRrDQAAQEIXzYup96V27dretgEAACBxemZCQ0Nl4sSJ0R6zfv362LcGAADA11OzAQAA/D6YKVKkiOvngIAA6d27tyxdulQGDhwoKVPGqagwAABAwgYzHTt2lAEDBoS53bNnT9m/f7+pQ6MBDQAAgN8GMz169JBx48a5br/xxhvSrVs36dWrl7Ru3VpeffXV+G4jAABAlDweE5o3b575t3Tp0jJkyBBxOBxmiOm5556TO3fumCBGbxcrVsx17EsvveTp6QEAABI2mHEGJufOnTM5MocPH5aqVaua4OaFF14w9+XKlcsU1iOIAQAAicXrbF3tdZk5c6bMnj1b2rRpIzNmzHDdV61aNdmwYUN8txEAACD+cmb69Oljask0bdpUVqxYIcOGDXPd16JFCxk6dKi3pwQAAIi1ABFxSBIXFBQk169fl0yZMsmNGzckOXnkWOTrJiARBQY05XonI7y/k5fk+P4O8vDvN0XzAACA1ahwByRTWuAyT548EhjIdxp/oDNEL1++LLdv3/Z1UwDrEMwAydBjjz0mn376qaRNm9bXTUE469atk++//94ENwAsCGZ09pNWD9Yp3g8ePJCNGzdKv3795MSJE2GOe//996V79+5m6vfevXvl3//+t2zdutVn7QZspvWgOnToIDdv3pQvvvhC7t696+sm4f/rKStVqpS0atXKXI/vvvuO6wL4ezCjXds6E0o/TDt16iTp06eXr776SlavXi1PPPGE3Lp1yxzXtm1bGTFihLz++uuyZcsWU+NGZ1GVKVNGzp4966vmA9bKkiWL+aP5n//8x9SLgv84duyY+VeLkGrZC4acAM/4bLD80aNHUrNmTVm4cKFcunRJTp06ZXpgdBFLrSrs9MEHH5hvKAsWLJDg4GCzbIJmNnfu3NlXTQesnx2g9P0E/3Pw4EHzb44cOXzdFMAafpX5lz17dvOvc/qVfoPUHpi1a9eGOU5v69AUgNgNM6mHDx9y+fyQDrm7/z8BsCiY0WGnUaNGye+//26WRFA60yKyb5Dak5M7d+4oz5U6dWrz7dN9A2AXXeetbNmyvm4GAAv4zWymSZMmmQ+u6tWrmyGo6Oj90X1r0STiQYMGJUArgeStcOHCUqhQoUh7EzZt2hSvz9WtWzfJnz+/VWu9FS9eXFKlSiX79+/3dVOAZMUvghlNRGzWrJnUqVNHjhw54tp/8eJF82/OnDkjTCv966+/ojyfJhaPHj3adVt7ZnSBTABx0759ezMD8bfffguzX2dG6RIn8Uk/C0JCQsQmOtNSc11eeeUVXzcFSFZ8HsyMHz9eXn75ZalXr578+eefYe67evWqHDp0SGrVqmUWuHSqXbu2TJ06Ncpz3rt3z2wA4p9+MdAvHjEpV66cycvRGVMFCxaUjBkzmtIKzvtCQ0Nds3fU448/LhkyZHAds3TpUkmTJo3r/pIlS5oeWf1MKFq0qPmSsmfPnjA9ue7H6PkyZ85sjtF26FC2zpTUzwZNso2sjot+UdJJCGfOnJHz58+Huc95bn2snlt/nwMHDsj9+/ddvVZ58+Y1z6mfWUqf27aADLCRT4OZcePGmZoKdevWlX379kV6jObRaC+LfrBpbRmdmp0tWzaZOHFiorcXQMyyZs1q3q/6x19nKeofd+1l0aDjxRdfdPWeHj16VHr06OF6nM5Q1CDHeUz4Yaa+ffuac+r5NDjRulN///23NGzYUE6fPu06RicN6OQB7S3Sx2sw0aVLF/nyyy9NyQcNrPTzpkGDBq5kW82z088UfS4NvjQw2bFjhykJce3aNde5S5QoIenSpTNBjfbAaEBWv3598/z6OVaxYkUzzOQc5tZerF27dvGyAZJqMKMBSdeuXc0H3O7du8Pc969//ctUwFTffPON+WDS2/qtST+EGjVqZD4kASQ+/WPu7HlwunLliqtHZciQIaaysAYEWkZB8+C0qu3KlSvj/NxVqlSRli1byty5c02vjQZN+qXIPa/mqaeeMs+5fft203ujvTTz5883j9WeEv3s0UBKv0hNmzbNPEarIWvCseYDaZu1/Vo2Yvjw4WHKQGiwoj3DWvNKg5YNGzZInz595L333jMlJCpVqsQwE5Ccghn98NOKl5EJP2V05MiRZgPgexoMhE+w37Ztm/mjrv75z3+aP+4aFCit7B0fgYz6448/TCCjtHLxZ599JqtWrTK9Nc4eFC3doIGMs8yD5vdoT4oGMs7PHp0x6ZwppcNP+gVKC3jqMJQeq5v2BOvv4k6DMg1klA4vLV++3KMhNwBJeJiJOhdA0sqZ0aEX7Q0JX1lYe0d0iCiuIjuv0jwXLevgLN3g7s6dO2bIKfw+rTqudLhKg6HmzZub3D137hMSIisTocNMzvMASMYJwACSDu0J0aHj8LWdwt/W5Nvw5RU0byUmUZ03Lkm2ziUDhg4dGmaiAQB7+E3RPAD206EfzZ154YUXXPtSpEhhkmTdadkFTcR1576MSVQqV64cJqDRZGE9lzMBODZ0eEqTdMMPKSlvC25qYORJUAYgftEzAyDOCcDO3BgdOh44cKDMmTPH5MxonkrHjh1dS5U46f2LFy82s310qEiTcTWHRc8R7QdWypSyZMkSGTNmjEkw1mRjPUdMhTZjorOdNP9FF3ecOXOmSQB2DjnpCuOe0kCuTZs2JiFZc3OYmg0kDoIZAB47ceKEySOJrMJ2kyZNzNTnRYsWmRlH7dq1M1OtdcaR1pB68sknXcfqyvetW7c2q0PrDCANJDZv3mxyX6IrmqfDQMuWLTO1qbTXpFOnTvLTTz+57tcaMNoT5E6r8WpuS/igw72Qpj63zoJ69913TTLw5cuXTdJyTOfWHiHn8itKj9elVtq2bSuZMmViajaQSHTQOmLlqCRGP/T0W6J+uDgXsUwuHjkW+boJSESBATFX4dXpx9qjoT0oiVXiQOvKaLDgrCETG1qeQXtm3nzzTUnKvPn/4f2dvHjy/k6uf7/JmQEAAFZjmAlAgjt+/Lip5xIXkQ3zAIAimAGQ4LSSd1yNGDEiXtoCIOlhmAkAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAYAAFiNYAaANYYPHy5nzpwxCzrWrl3b180B4CeoMwPAGLV3S6JeiZ5PVPHq+Bo1akjXrl3lmWeeMUX47t2759XjP//8c6lZs6ZZedtd6dKlzarZet/27dvNPl02QReL7Ny5szm+R48eMmnSpAjnbNy4sXzyySdStGhRs27V4MGDZf78+a77PT0PgLihZwaAFUqUKCHnz5+XAwcOyN27d8Xh8G5ZuVSpUkmaNGki7NfKxLpKtnuFYl3/SRez/PTTT81zaVASni6QqQtf6uKSpUqVksmTJ8vs2bOlWrVqXp0HQNwRzADwe//5z39kwoQJZlVtXQFbh5qU9nasXbtWLl26ZFbm7t27d5yXTXAuaqkreq9ZsybKY3r27GlW2x4zZoxcvHhRxo8fL+vWrZMPPvjAq/MAiDuCGQB+r0uXLmaIRodysmTJYoZ1NGhZtGiRrF+/3vSMNGvWzKysW7169URpkz6PBlLuVq9eHaZnBkDioM8TgN97+PChPHjwwAwt6XCNypYtm+TIkcMM7fz9999m+/DDD6M9T/ny5U3PjruAgIBYtSl37twSHBwcZp/e1jbpgpjaZgCJg54ZAFa6cuWKzJ07V5YvX25mOTVs2DDSnBh3e/fuNT077luVKt4lIrt79OhRpLdjGyABiB2CGQDWatmypUmy1R4bXVVbZzk9+eSTUR7v7Nlx37ydFeXeC5MzZ84w+x577DETZGkvEoDEQzADwGqat9KvXz8TxBw8eFDef//9RHneLVu2SK1atcLsq1OnjtkPIHERzACwUsmSJWXixIlSpkwZkwxcuHBhKViwoJw8edLc/95770XIj4lP48aNM4X72rZtK+nSpZM2bdpI/fr1ZezYsQn2nAAiRzADwEpHjhyRHTt2yIwZM0zQ8ttvv8myZctMcTylNV20fkxsVKhQwZxTN82r0enX+vPUqVNdx2zYsEH++c9/ykcffSQ3b940tWQ6dOggq1at8uo8AOJOs9S8qzxloaCgILl+/bqZtnnjxg1JTh45Fvm6CUhEgQFNYzymUKFCMmTIEBk4cKCcOnVKbKG9LzpL6P79+x4fr4XynLOf9LG6L7LHa+Kw8zj3fVHNqgpPE36jKuLnzXm8/f/h/Z28ePL+Tq5/v5maDcAKOlMo/OyhmI53D1A0gIhqunT4QCaqfVGJrhqxN+cBEDsMMwEAAKsRzAAAAKsRzAAAAKsRzAAAAKsRzAAAAKsRzAAAAKsRzAAAAKsRzAAAAKsRzACwhq599M0338jcuXPliSee8HVzAPgJKgADsELx4sVlyZIl0rdvXzl+/LhcuHDBq8e3a9dOmjb9v3LwupTAuXPnzPlWrlwZ4dgcOXKY4ytXrmyCJ13zKbzcuXNLly5dpGjRonLixAkZP368Oae35wEQdwQzAHyyzo+368xoQHD+/HmzWGNsaE/Ok08+KT169DDrND399NOyePFi6d+/v4waNcp1XLNmzUxgMn36dHn++edl9erVEc6VK1cu2blzp+zevVvmzJkjzZs3N7efeeYZV0DjyXkAxA+CGQB+791335WOHTuano558+aZhefeeustsxJ1p06dpFy5chIcHGxWo961a1eU57l27ZosWLDA/KxDVVmzZpXu3buHCWa2bNkijz/+uFmQUp8zMn369DErZWsQo708U6ZMkb1795rA6L333vP4PADiB8EMAL+3adMmE7Boj8gPP/zgWrxRh4hCQkLMPg1MvvzyS+nWrZvpJfGErkqtw0XuNCiKyYsvvigLFy50rXytC1hqkNW6dWuvzgMgfhDMAPB7e/bsMVuDBg1cPSvZs2eXihUrmlyao0ePmn3/+c9/JGPGjB6dU4eaGjVqFG1PTlSKFCkiZ86cCbNPbxcqVEgCAgKiXUUbQPxjNhMAK125ckWOHTtmhohq164tadOmlUePHpkhqOiCEO1B0V4VDYAyZ85shqu8lSZNGrl9+3aYfTrsFBgYKKlTp47V7wMg9ghmAFhJez9q1KghBw8eNEnBly9fNjkzOtwUXQCkQ1Ka47JmzRrJly9frIIPzb0J/zzaUxQaGuoaAgOQeAhmAFhLp2drMm6FChWkVKlSZoZSv379YkwAnj17trRv315WrVol06ZNM0NO3tAhL50Z5e6pp56SP/74I9a/C4DYI5gBYCXtVdHZRE5nz541Sbc63KSaNGlihpSi88EHH5gZRx06dPDqubVn5x//+IfJ11Faa+all14y+wEkPhKAk7gx+3L4uglAgrhx44a0adNGxo0bJwcOHDDJt+qLL75wBRjuwU5ktCaMzoD6+OOPTSCieTAa3DinamfIkMFMq9bKw5s3b5aRI0ea/ZMnT5bq1avLjh07TK0Z7ZVZunSpTJw40XVuT84TV7y/gf9DMAMgVkXsEtsvv/zimrWkNNH35ZdfNj00ZcqUMTkzv//+u2sm0aJFi+TkyZOu4zUAcc6Ecjd06FBTEyYoKMgEM3///bfJq1HOf5V7dV99jrZt28pnn33mqgCsuTvuPDkPgPhBMAPACloTRrfwNDiILEDQJQ90c9q3b1+UPTzuQY57Yb2YHD582GyR8eY8AOKGnBkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1iuYBsEaWLFmkXr16ZoXqxYsXy/nz533dJAB+gGAGgBWyZs0qf/75p1mZWpcPWL9+vVePr1KlipQvXz7Cfl1T6cyZM67buhr2c889Jxs3bpT9+/dHeq4aNWq4ljHYsGGDawkFd56cB0D8IJgBYKxdeShRr0SdBiW9Ol4XaQwMDJSGDRvG6vlatWplFqacM2dOmP2bNm0ywUyFChVk/PjxkjFjRilZsqT07NkzQhCSKlUqmT9/vllY8tdff5Vq1aqZNZl0he67d++aYzw5D4D4RTADwO/VrFlTmjVrJgEBAdKpUycJDQ2V//3vf+Y+DSzKli0rwcHBphdE74vK2bNnpXPnzpHelyJFCunVq5dZdPLq1auRHvPuu+9K5cqV5YknnjBDXLlz55a9e/dKt27d5PPPP/f4PADiFwnAAPxegQIFzJYmTRoTvGgwob7++mtZvny56a3RgEIDiMKFC8fqOXbs2GEeH53XXnvN9Mw4c3UuXrxoenp0vzfnARC/6JkB4PemTp1qhm3y5s3r6lkJCgqSd955RypVqiS7du0y+woVKmSGoqKiicPas+O+svWMGTM8bof2AIUfptIhpLfffjsWvxWA+EIwA8BK9+7dM0NKdevWNUM99+/fl1OnTkX7mHTp0pmeHScdmvKGBlAhISFh9ulQkvYY6ebMmwGQuAhmAFhJA4dXXnlFhg8fLh999JFs3rzZ9OBMmTIlVjkznrhz544JaNxlypRJHj58SCAD+BA5MwCstWzZMjMFukSJEjJr1iwZN26cdOnSJcGe78iRI1KkSJEw+/T2sWPHEuw5AVgQzJQqVUrGjBljPpScSX3habfwxIkTZd68efLJJ5+YwlkAkjftEcmZM6crEfe7776TdevWmeBGlStXLkx+THxYuHChmVWlw1Uqbdq00rJlS7MfQDIdZurfv7+p+zB37lwzG0G7i8PTolP6AfXtt9/K7NmzTcKffnhUrFgx2imYAJI2He5Zu3at+XzQJFydxaSfI1rzRWml4LFjx8qkSZM8Ol+OHDnMZ4tKnTq1VK9eXR48eGB6XVatWmX2f/HFF2Zoa/Xq1SaAady4sSmYN2LECK/OAyAJBTOTJ0+Wzz77TPLlyycDBgyI9Bi9X3ttnF3HWsL83Llz0r59e1OYCkDyoNV/p02b5rqtnwNaoO7VV181s4z++usv04t7+PBhc79WCtYeXffieJcuXfIoOdi9hs2jR49cx2jyr36R0tlLWgH4559/lu+//97MivLmPACSUDCjHz7R0S5cLZalgYvT9evXzbcb/QZGMAP4riJvYtOCeLq5u3Xrlhleioz22ujmFH5KdXhaBdiT5OAbN27Il19+GefzAEhCOTPR0SJZKVOmDLNuinNGQnSFsbRrV7ug3TcAAJA0+XUwo0GJCp8bc/v2bdd9kenXr5/pwXFu2h0NAACSJr8OZpzFqbJlyxahimd0a54MGzbMzHRwbpqTAwAAkia/Dma0R0UT9jTJz53e3rNnT7SVQXVc230DAABJk18HM87ZAJoArL0x6vnnn5enn35afvzxR183DQAAJPfZTPXr15eePXuaNU3U559/LleuXJGffvrJlCVXWqZci+lp5U3d9GfNidFplgAAAD4NZrTQlRa1Uu5Fp44ePRom2feFF16Q0qVLS65cucxjvF0cDgAAJF0+DWbOnz9vNk8cOHDAbAAAAFblzACAuwwZMkjBggVdw9MAQDADwAqBgYEyf/58uXDhgqxfv16eeeYZrx6fNWtWKVSoUIRNK42Hfx4NljJmzBjluVKkSCG5c+c2RT2joufV0hAAkvgwEwD/cW9wr0R9vtQff+HV8Q0aNJC6deuaulGxKbegkwnefffdCEPb7dq1M8se6AKRugyBzp7U6uNdu3aVr7/+OsJ5dP8nn3xifg4ICJBPP/1URo4cGaadAwcOdK3HdPnyZfnggw9k3rx5XrcZgGfomQHg97RwptaX+vvvv83P+fPnD3O/lm6IrpfESScQFClSJMzmXL+pRo0a5hy6yrVWDo9Mo0aNTODSunVryZIli1kdW4OZl156Kcwxffv2Nffr9tVXX8nMmTNdi08CiH8EMwD8nvZs9OrVy/TKrFu3ThYsWGD2v/LKK2bY6eDBg6bApi46Gdu12LTn5OOPPzZrv0VFe3ZWrFghy5YtM7d10dulS5ea/U49evSQzZs3u1bJHjdunOlJqlevXqzaBSBmBDMA/J7WlhowYICcOnXK9KZovkyqVKlM8czevXtLzpw5zbZmzRopWTLq1b91TTf3fJm8efN61Y5KlSqZQMWdruSt+6OiJSU0wPJ05iYA75EzA8BK6dOnl3Tp0snx48fN7QcPHpiCm9EpVqyY6dlxOnnypNSpU8fj59S8Gh3qcqc5MZkzZzbB1f379yM8ZuLEiXL69GmTvAwgYRDMALDStWvXZPjw4bJy5Uoz9KNBys8//yxnzpyJNmcm/Fpv3tCho/C5ORrEqIcPH0Y4XvNlNBendu3aEhoaGuvnBRA9hpkAWD38pL0tmu9StWpVkzujs4kScvFbnZLtTm9fvHjRlSPjNHr0aHn99ddNe/bt25dgbQJAMAPAUloPRmkuiubOtGrVSlavXi2vvfaa2a95KpoXE5+090eXV3HXsGFDU/fG3ahRo+Stt94ygczu3bvjtQ0AIqJnBoCVihcvboKLFi1aSKlSpUxQoYm4O3bscNWP0ZwYT+lwkTMxWAMlnQKuP2uejJMuhluuXDkzvKVTrXVatiYj622nYcOGmdlNHTp0MPk1znNq0T4ACYOcGQBW0OnN7tOmDx06JB9++KEpYle2bFmTiDtkyBCZMGGCuV9rxbgHM1euXIl2RpHOglq0aJHrWA2GdNOp1++9954r56Z+/fqmKJ7Wljlx4oQ8//zz8vvvv7vOo1OwddhJh5nc6bRxbR+A+EcwAyBWFXkT27Rp08wWflq0bpH5/vvvzeYUUyCheS067TsmW7ZsMYXxovLss8/GeA4A8YthJgAAYDWCGQAAYDWCGQAAYDWCGQAAYDWCGQAAYDWCGQAAYDWCGQAAYDWCGQAAYDWCGQAAYDWCGQDWeOedd+TXX381ywpUrlzZ180B4CdYzgCAMXjBH4l6JT5uVt6r459++mkZN26cNG/eXI4fPy6nT5/26vF9+/Y1K1mrBw8eSEhIiAmK5s6dK8uXL49wvC5a2blzZxM06YKS4ZdScLZpwIABUrRoUbNOky4yuW3bNq/PAyBu6JkBYIXy5cubhSaXLVtmFpkMDQ316vG5cuUSh8NhgqFWrVpJ//795cyZMzJ9+nSZPXu2pEiRwnWsBj3jx4836z7ly5cv0hWvdWHK9evXm3Noj9GxY8dk7dq1ZlVtb84DIO4IZgD4vU8++cT0euTPn18OHDggmzdvNvuLFStmFpPcvn27LFmyxAQp0bl7964JhPQcOlylPSU1a9aUpk2bSrdu3VzHaYDz3HPPmZWuHz16FOm5evfubc7VvXt32bp1q/Tq1Uv27t1reoC8OQ+AuCOYAeD3vv76a5kwYYJcuHDB9Ky8+eabZv/KlSvNkJH2jIwZM0b+8Y9/mODEG7pa9oIFC1znVPfu3YvxcXXq1JFffvklzD4NqHS/N+cBEHfkzADwe3/99ZfZ7t+/b3pDVPbs2aVw4cIycuRIOXz4sNm3atWqMMNFntqzZ4/pnfGG9hJpcOXu4sWLkjdvXgkMDKQnBkhE9MwAsNLff/8tW7ZskZkzZ5qemVKlSpn9Dx8+9PpcGiSlTOnddzsNmsL3vOgwlvM+AImHYAaAtXRI58svv5RatWrJhg0bZOfOnaa3xluFChWSc+fOefWYK1euSI4cOcLs09s3btwwwRGAxEMwA8Ba2hOiCcCtW7c2wz4aRGhirjfSp08vLVq0MLOkvKFJx+Fr3VStWlV27Njh1XkAxB3BDAArFSlSxMwcypgxo7mdKlUqSZMmjVy7ds3c1oRenbUUnTJlysiiRYvMlG2d2eSNSZMmyQsvvOBK+K1evbo0btxYJk6cGOvfCUDsEMwAsNL58+dNIKPF806ePGmSb7Xmi07hVtmyZXPl0TjpbQ1wDh48KJcuXZJ169bJ0aNHpWLFiuZ87kGOHqdbUFCQfPjhh+bnsWPHuo7RGVCDBg0ywZA+txbe0+eeNWuWV+cBEHcBIuKQJE4/RK5fvy6ZMmUy49nJyai9W3zdBCSink9U8Sg/ZMiQITJw4EA5depUorQrPmTOnNkEKFpp111AQIAZYtKE4Nu3b7v2Z8mSxRTKc85+ypkzp3m80unc2oNz+fLlSJ9Le3giy73Rz5HwM5jSpk0refLkMQFN+EJ+3pwnNv8/vL+TF0/e38n17zdTswFYQYMP5xCSOx0i0h6Z8HS5At2ctCdGN084i+t54s6dOxECrNicB0DsMcwEAACsRjADAACsRjADAACsRjADAACsRjADAACsRjADAACsRjADAACsRjADAACsRtE8ANYoXbq0WRQye/bsMmHCBDly5IivmwTAD9AzA8AKumSBrkj92GOPmTL/4ZcOiEnz5s2lV69eEfbrkgdjxoyRggULhtmvC1e2atVKRo8eLdWqVYtyxe2OHTvK8OHDpVOnTq5FL909/fTT5nk/+ugjadKkiVdtBuAZemYAGA8Xt0vUK5GiyXdeHV+jRg2z/lK3bt1i9Xy1atWS2rVryxdffBFmf44cOaR79+4yY8YMs2ilqlu3rvzwww+ydetWE4AcO3ZMNm3aFOZxulaM7tMlCxYvXizt2rWTHj16SJUqVeTq1avmmJ9++kmKFy9uFrTUZQ++/vpr81wNGzY060MBiB8EMwD8nvaQtG/f3iw6p70oN2/eNAsxpkyZUlq2bCnlypWT4OBgmTdvnpw9ezbOz6c9P7qStp7TGZiE17NnT7OYpa7EfevWLfn8889l//790qdPH+nbt685ZtSoUbJ7927XY7799ls5fvy4vPzyyyZ4AhA/GGYC4Pe0R0a3+/fvy8mTJ10LSy5atEgGDBhgej10teklS5ZI2bJl4/x82hOjgUx0mjVrJvPnzzeBjNIVu3/++WcznOXkHsgobbcufpkvX744txHA/4+eGQB+b/Xq1VKsWDGTfzJu3DizL2vWrGa4RpOCDx48aPZlyJDBbFHRIEJ7dtxpMnFslChRwgxFhQ+CihYtGuVjdMhKh7U2bNgQq+cEEDmCGQBWun79uuk96dq1qxni0R4b7SVx9pRE5t69e+Y4d9qrExvp0qWTGzduRGiTDn2lSZPG5NK40yDnu+++M7Owtm/fHqvnBBA5ghkAVnr48KHUr19fPvzwQ9m5c6cJLKZOnSpDhgyJMkC5dOmSq2fHSYelnDku3tC8Hc2Zcae9RRowhQ9kdAhMe5c0EbhLly5ePxeA6BHMALDW3r175dVXX5WAgAAzi2j69OkmmBg8eHCCP7cm+2ryrzu9feDAgTD7dMq3BjHaG9O6dWsThAGIXyQAA7BSzpw5pUKFCuZnh8Mhmzdvlj///FNy585t9tWsWTNCfkx8mjVrlkn21bo3SnNhdJaS7ncqUKCACWS0Ps5rr71GIAMkEHpmAFhJA5iJEyeaIR3tJSlcuLCZTq1To5UGOlrTRWu/xKZAn069dubG6PRvTUD+/fff5ccffzT7v/rqK2nUqJFs27bNBCwaPB06dChMALVw4ULJkyePXLx4MUx9m/Xr15uZUADiB8EMgFgVsUtsWqDOPRfm8uXL8txzz0nVqlVN3svy5ctNz4jmsjgDBg1mnLQGTWSJtxcuXDDHuScGa4DkvO0Mjpw5N046nKU5Ow0aNDDJvVo3ZsWKFfLo0SPXMVokL7LZVVeuXInj1QDgjmAGgBX27dtntvB0eEm38LQXRTenqKZDa2ARPik4skThqHqHNICJihbJA5DwyJkBAABWI5gBAABWI5gBAABWI5gBAABWI5gBAABWI5gBkhmdgaN0DSH4H13XSVEpGPAcn2ZAMqPTju/fvy8vvfSSqb3y4MEDXzcJWucnRQpTTbhVq1amno4W2gPgGYIZIJkJDQ01VWq1Mm758uV93RyEc/DgQRk2bBhBJuAFghkgGdLic++//75Z30gXaYR/DP9dv35drl275hoKBJCEghldG6Vx48aSK1cus0puVJU8AXjXQ3P69GkuGQDr+X0CsK6Au2fPHhkwYIA888wzMnv2bJkyZYqvmwUAAPyE3/fMjBgxQm7cuCFVqlQxC7vpgnIa3MyZM0cWLFjg6+YBAAAf8+uemcDAQGnRooX8+OOPJpBRf/75p2zcuNFk/AMAAPh1z0yBAgUkY8aMcujQoQjZ/s8++2yUj0udOrWrVoMKCgoK829ykjowha+bgESUHF/jyRnv7+QlOb6/gzz8nVPa8EuEhISE2a+3o/sF+/XrJ4MGDYqw/9y5cwnQSsB/vH/9uq+bACCBJOf3d1BQkEk5sTKYuX37tvk3U6ZMYfZnzpxZbt26FeXjtEbD6NGjw+zLli2bXLlyJYFaCn970Wvgmi9fvmhf/ADsw/s7ef6fnz9/Ptpj/DqYOXXqlKmEWbRoUVm5cqVrv94+cuRIlI/T/Bpnjo0Tf9SSH/0/5/8dSJp4fycfNzz4UurXCcC6NsmSJUvkjTfecBX2KlSokNSqVcuUYQcAANAIwa9LTT7++OOyefNmUyxv27Zt8tprr5lemUaNGsmjR4983Tz4aZekVlLV4Ul6ZoCkhfc3rOuZUcePH5dy5crJwoULTYnv/v37E8ggWnfv3jUJ4PovgKSF9zes7JkBAACwumcGAAAgOgQzAADAagQzAADAagQzAADAan5dNA/wlK6m3q5dOylYsKCkTBn2Zf3999+b2XAA7MT7GzEhmIH1SpYsKTt27JDt27fLvn37TLFFdzdv3vRZ2wDEDe9veIJgBtZr1qyZzJ8/X1q3bu3rpgCIZ7y/4QlyZmA9rQR98OBBXzcDQALg/Q1PEMzAeqtXrzZVocPnygCwH+9veIJPf1gvd+7ckj17dvnjjz9k1apVcuvWrTD362KlGzdu9Fn7AHjnxRdflJo1a7pu8/5GTAhmYL38+fPLiRMnzM+lS5eOcP/OnTt90CoAcXlPV6xY0XWb9zdiwtpMAADAauTMAAD8mtaPypYtm/k5RYoU0qVLFxk+fLgUK1bM102Dn6BnBklCYGCgKZpXv359yZMnj5w9e1YWLVokM2bM8HXTAMRBjhw5ZO3atSaH5urVq9K/f3/p0aOHHD58WIoUKSJFixaV0NBQrnEyR88MrKff1PTDbvTo0WYap+bIpE6dWr777jv5+eeffd08AHHQsmVL8/7WQEa9+eabpqZUtWrV5MCBA9KwYUOuL0gARtL4sMuXL5/5hnbp0iXXfv3WtnXrVvONbsOGDT5tI4DYyZs3r+t9rb2u+l7X4EZpMKOzGQF6ZmC98uXLy/Tp08MEMs4ZEDrUpPcDsNOhQ4ekefPmJmjp2rWrCWScS5aUKFHC3A8QzMB62v2sH2qR0f1XrlxJ9DYBiB9z5swxOTEXLlyQzp07y6effmr2lypVSnLlyiXr1q3jUoMEYNivUKFCprt58uTJ8uOPP0pwcLCpU/Huu++a8fTixYu7xtsB2Klw4cJy+fJl18Kx+h4PCAiQM2fO+Lpp8BMONq6B7a+BmjVrOvbu3etwt3XrVkeFChV83jY2rgGvAV4DvAYkQa8BU7ORpGiCoHNqtvbQAEgaNGdGh5YyZ84cZv++ffvk2LFjPmsX/AcRI9eA1wCvAV4DvAb89jXw+eefO+7fv2+2u3fvunpf79y54+jSpYvP28cmPr8G9MzASs2aNTMF8ubNmydBQUHm56joMWvWrEnU9gGIH7Vr15Zp06aZ9/jbb78tFy9elG+//Va6d+8ur7/+upmtePfuXS53MsdCk7BSlixZTAJgxowZXT9HRY8BYKfKlSvLlClTZP/+/eJwOCRVqlRy7do1GTx4sFStWtWssD1//nxfNxM+RjADK+msJd2c5c4XLlwY6Ywlvc9ZkwKAfbJnz256Y5TOZtIiek6aK6NF9ADqzMB6ffr0MesyeXsfALts27ZNXn75ZXnuuedMj81LL70kR48e9XWz4AfomUGSpkNMzroUAOyzZcsWM6yktEDe0qVLZfPmzWZx2alTp8ry5ct93UT4ARKAYa2mTZtK3bp1pUaNGnLr1i3ZtWtXmPt1Cqd+i6tXr55s377dZ+0EEL806V9zZ6juDSd6ZmAtzYcpVqyYSQBOly6d+dlJEwVDQkKkU6dOBDJAEnPjxg1fNwF+hp4ZWK9Vq1amG5ruZiBplV7wBKUXoOiZgfVmzZrl6yYAiEcxlVtwR+kFKHpmkGRQ7hwAki+flyFm4xpQ7pzXAJ8DvAbcXwOFChVy5M2bl9cFrwuHJ9eAOjNIEuXO27RpI08++aSMHTtW+vfvb7qpBw0aJKdOnZL//ve/vm4iAC+9//770rp1a9ftrl27yhtvvMF1RKQIZpCky52fPHnSlDsHYLcCBQqYoWQgMgQzSBLlzoODg13lzt0/8Ch3DgBJH8EMkhTKnQNA8sPUbFiPcudA0tS5c2dp0qSJ+blo0aJy7949122nCRMmUJ4BTM1G0kS5c8D+Ypie5LvNmDGDgpkgmAEAAHZjmAlWotw5AMCJYAZWotw5AMCJ5QwAAIDVmJoNAACsxjATrETODADAiWAGViJnBkg+AgMDpV27dlK/fn3JkyePnD17VhYtWmSmZQOKnBkAgN9KkSKFrFmzRipUqCCLFy+WixcvmnWaGjduLMuWLZOWLVv6uonwA/TMAAD8lgYr+fLlMxWAL1265NpfpEgR2bp1q9SsWVM2bNjg0zbC9whmYHXOzLx580y1X/05KnqMfrMDYJ/y5cvL9OnTwwQy6sSJE2aoSe8nmAHBDKzOmcmYMWOM+TN6DAA7Xb16VZ599tlI7ytRogRfVGCQMwPr5ciRQx4+fGg+9Ly5D4D/K1SokBw4cEAmT54sP/74owQHB5svL++++640bNhQihcvzvsb1JmB/fr06WNmOnh7HwD/d+rUKRO01K5dW7Zv325ub9q0SYoVKyYNGjQgkIHBMBOSNB1iunnzpq+bASAONCfmiSeeMNOynVOztYcGcCKYgbWaNm0qdevWlRo1asitW7ci5M1kzpxZXn75Zfnuu+981kYAcdOlSxcpU6aMrFu3zmy7du3ikiICghlYS/NhtKtZE4DTpUtnfnZyOBwSEhIinTp1Ml3TAOz0xx9/SNWqVWXMmDGmV+bgwYOuwEa3v/76y9dNhB8gARjWa9WqlVy7dk2WL1/u66YASEAlS5Y0uTO61alTR3LlymUSgSdMmMB1T+ZYaBLWmzVrlpntkC1bNlfFUO2aHj58eJjeGgD2SpUqlemNzZkzp9kyZcokx48fl3Pnzvm6afATDjaugc2vgRw5cjj27t3ryJo1q7ndv39/x6VLlxybNm1ynD9/3pEuXTqft5GNa8BrIHavgUaNGjlWrFjhuHnzpuPYsWOOyZMnO958801H/vz5uaa8rxxu14APGa6B3a+BTp06Ob788kvX7QMHDjjq169vfl69erXjpZde8nkb2bgGvAZi9xoYOXKkQ82fP9/RokULR/bs2bmWvJ8c4a8Bw0ywXt68eV2lzjVBUNdxWbt2rbmtw0+5c+f2cQsBxNagQYNMnRl9L3/wwQdy/vx52bNnj4wdO1aaN29uhpsARZTLNbD6NfD66687du7c6cidO7dj2LBhjgULFrju0+7punXr+ryNbFwDXgPx8xrIkCGDo2PHjo4TJ06YHpuePXtybYX3F8EMLwLrPwhSp07t2Lhxo/lgCwkJcVSqVMnsL1WqlGPPnj2OwMBAn7eRjWvAayD2r4G8efOaLy3ffPON4+jRo+a9fvbsWcfUqVMdFStW5NoK7y+mZiPJKFy4sFy+fNlV8VeL6AUEBMiZM2d83TQAXhowYIAZPtZh4sGDB5tZS+vXr3fVlzly5AjXFC4EMwAAvzNy5Ei5ePGirFy5UkJDQwleEC0qAMNKzZo1k/r168u8efMkKCjI/BwVPWbNmjWJ2j4A8VcBGIgJwQyspEsY6DCSLiTp/DkqegwA+xQvXlzq1asX7TGHDx9mKBkGyVNcA14DvAZ4DfAa8Mv6MjFhNpPv/6/8YaNnBgDgl4YOHSrffPNNtMdcuXIl0doD/0UwA+vpirrdu3eXSpUqmQJa+uG2ZcsWk0C4d+9eXzcPQCxdvXpVTp06xfVDjAhmYLXWrVvLlClTZP/+/bJ48WIJCQkxi9FpQvC2bdukUaNGrmrAAICkiWAG1kqbNq2MHz9e+vTpI6NGjQpzn9aX0X2TJk2SEiVK+KyNAGLn2LFjDCHBKz5P3GHjGsTmNdC4cWPHjh07orxfK/+ePn3aUaFCBV5jvMZ4DfAa4DUgSfcasNAkrFW2bNlo68c8evTIVAwtV65corYLAJC4CGZgraxZs7pWy45KcHCwOQ4AkHQRzMBaKVOmNL0v0dH7U6VKlWhtAgAkPhKAYbXOnTtLkyZNory/aNGiMm7cuERtEwAgcRHMwFrbt28307Cjc/LkSdm3b1+itQkAkPhYNRsAAFiNnBkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAAGA1ghkAACA2+38TmaGoFJCXyAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } ], - "text/plain": [ - "Equipment fs.H101 fs.R101 fs.F101 fs.F102 fs.D101 fs.H102\n", - "Distillation 13.283334 13.552294 7.781332 0.000000 7.60743 3.32944\n", - "Two Flash 13.283334 10.755878 7.781332 7.781332 0.00000 0.00000" + "source": [ + "# Compare equipment purchase costs (actual capital costs)\n", + "\n", + "two_flash_capcost = {\n", + " unit.name: value(unit.costing.capital_cost / 1e3) for unit in two_flash_unitlist\n", + "}\n", + "distillation_capcost = {\n", + " unit.name: value(unit.costing.capital_cost / 1e3) for unit in distillation_unitlist\n", + "}\n", + "\n", + "two_flash_capdf = pd.DataFrame(\n", + " list(two_flash_capcost.items()), columns=[\"Equipment\", \"Two Flash\"]\n", + ").set_index(\"Equipment\")\n", + "distillation_capdf = pd.DataFrame(\n", + " list(distillation_capcost.items()), columns=[\"Equipment\", \"Distillation\"]\n", + ").set_index(\"Equipment\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "capcosts = two_flash_capdf.add(distillation_capdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "# Sort according to an easier order to view\n", + "capcosts = capcosts[[\"fs.H101\", \"fs.R101\", \"fs.F101\", \"fs.F102\", \"fs.D101\", \"fs.H102\"]]\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(capcosts) # view dataframe before plotting\n", + "\n", + "capplot = capcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Total Capital Costs\", ylabel=\"$1000\"\n", + ")" ] - }, - "metadata": {}, - "output_type": "display_data" }, { - "data": { - "image/png": "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Q0RERJLFIENERESSxSBDREREksUgQ0RERJLFIENERESSxSBDREREksUgQ0RERJJlaugCiIhIf7/8/SVDl0BN6mNDF2C0OCJDREREksUgQ0RERJLFIENERESSxSBDREREksUgQ0RERJLFIENERESSxSBDREREksUgQ0RERJLFIENERESSxSBDREREkmXQIBMQEIDk5GQUFxejuLgYCQkJ8PPz0y63sLDAli1bUFBQALVajT179qB9+/YGrJiIiIiMiUGDzB9//IHVq1fD3d0dzzzzDH766SccOHAAPXv2BABs2rQJY8eOxZQpU+Dt7Q0HBwdERUUZsmQiIiIyIgZ9aOTBgwd1Xr/55pt45ZVXMGjQIPzxxx+YN28epk+fjri4OADA3LlzkZ6eDg8PD5w6darWfZqbm8PCwkL7WiaTNd4bICIiIoMymmtkmjVrhmnTpsHKygqJiYlwd3eHubk5YmNjtetcvHgRCoUCnp6e993PmjVroFKptO3q1atNUT4REREZgMGDTO/evaFWq1FeXo7PP/8cEyZMQFpaGuRyOcrLy1FcXKyzvlKphFwuv+/+NmzYAGtra23r2LFjY78FIiIiMhCDnloC7o2y9OvXDzY2Npg8eTIiIyPh7e1d7/1pNBpoNJoGrJCIiIiMlcGDzN27d5GRkQEA+P333zFgwAAEBgZi165dsLCwgI2Njc6ojL29PfLz8w1VLhERERkRg59a+qtmzZrBwsICSUlJ0Gg08PX11S7r1q0bHB0dkZiYaMAKiYiIyFgYdETmvffew+HDh5GTkwOZTIbp06fDx8cHI0eOhEqlQnh4OEJDQ1FUVASVSoXNmzcjISHhvncsERER0ZPFoEGmffv2+Oqrr9ChQwcUFxfj3LlzGDlypPZOpaVLl6Kqqgp79+6FhYUFoqOjsXDhQkOWTEREREbEoEFm/vz5D1xeXl6ORYsWYdGiRU1UEREREUmJ0V0jQ0RERFRXDDJEREQkWQwyREREJFkMMkRERCRZDDJEREQkWQwyREREJFkMMkRERCRZDDJEREQkWQwyREREJFkMMkRERCRZDDJEREQkWQwyREREJFkMMkRERCRZDDJEREQkWQwyREREJFkMMkRERCRZDDJEREQkWaaGLoAaj/fwS4YugYiIqFFxRIaIiIgki0GGiIiIJItBhoiIiCTrkYKMubk5zM3NG6oW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", - "text/plain": [ - "
" + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Utilitiescoolingheating
Distillation60.192008367.404722
Two Flash47.028803372.093536
\n", + "
" + ], + "text/plain": [ + "Utilities cooling heating\n", + "Distillation 60.192008 367.404722\n", + "Two Flash 47.028803 372.093536" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Compare operating costs (per year)\n", + "\n", + "two_flash_opcost = {\n", + " \"cooling\": value(3600 * 24 * 365 * m.fs.cooling_cost / 1e3),\n", + " \"heating\": value(3600 * 24 * 365 * m.fs.heating_cost / 1e3),\n", + "}\n", + "distillation_opcost = {\n", + " \"cooling\": value(3600 * 24 * 365 * n.fs.cooling_cost / 1e3),\n", + " \"heating\": value(3600 * 24 * 365 * n.fs.heating_cost / 1e3),\n", + "}\n", + "\n", + "two_flash_opdf = pd.DataFrame(\n", + " list(two_flash_opcost.items()), columns=[\"Utilities\", \"Two Flash\"]\n", + ").set_index(\"Utilities\")\n", + "distillation_opdf = pd.DataFrame(\n", + " list(distillation_opcost.items()), columns=[\"Utilities\", \"Distillation\"]\n", + ").set_index(\"Utilities\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "opcosts = two_flash_opdf.add(distillation_opdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(opcosts) # view dataframe before plotting\n", + "\n", + "opplot = opcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Operating Costs\", ylabel=\"$1000/year\"\n", + ")" ] - }, - "metadata": { - "filenames": { - "image/png": "C:\\Users\\dkgun\\src\\dangunter\\examples\\idaes_examples\\notebooks\\_build\\jupyter_execute\\docs\\flowsheets\\hda_flowsheet_with_costing_doc_23_2.png" - } - }, - "output_type": "display_data" - } - ], - "source": [ - "# Compare equipment purchase costs (actual capital costs)\n", - "\n", - "two_flash_capcost = {\n", - " unit.name: value(unit.costing.capital_cost / 1e3) for unit in two_flash_unitlist\n", - "}\n", - "distillation_capcost = {\n", - " unit.name: value(unit.costing.capital_cost / 1e3) for unit in distillation_unitlist\n", - "}\n", - "\n", - "two_flash_capdf = pd.DataFrame(\n", - " list(two_flash_capcost.items()), columns=[\"Equipment\", \"Two Flash\"]\n", - ").set_index(\"Equipment\")\n", - "distillation_capdf = pd.DataFrame(\n", - " list(distillation_capcost.items()), columns=[\"Equipment\", \"Distillation\"]\n", - ").set_index(\"Equipment\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "capcosts = two_flash_capdf.add(distillation_capdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "# Sort according to an easier order to view\n", - "capcosts = capcosts[[\"fs.H101\", \"fs.R101\", \"fs.F101\", \"fs.F102\", \"fs.D101\", \"fs.H102\"]]\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(capcosts) # view dataframe before plotting\n", - "\n", - "capplot = capcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Total Capital Costs\", ylabel=\"$1000\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Costs in $1000:\n" - ] }, { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Utilitiescoolingheating
Distillation60.192008367.404722
Two Flash47.028803372.093536
\n", - "
" + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Costscapitaloperating
Distillation45.553829427.596731
Two Flash39.601876419.122339
\n", + "
" + ], + "text/plain": [ + "Costs capital operating\n", + "Distillation 45.553829 427.596731\n", + "Two Flash 39.601876 419.122339" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAHvCAYAAABQTQWGAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOyVJREFUeJzt3Qd40+X+//93W1pEaJlSoEyZhyUoyFAQBARBZCkOQIGjMhQXKoILxzmAylBQ4QgoIoKIAoIoKFPZQ7HsvUcBmWVD/tf7/v6TX1M6krY0zf15Pq4rVzPupHc+SZpX7xkiIi4BAACwWGigKwAAAHC9EXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AC4rj788EN57rnnsuzjOdnLL78sPXv2lKwiJCRERo4cKU2aNAl0VWChEFZaBnzXq1cvqVu3rjz66KPicl27SPmIESPkn3/+kTfffPOa+yi9z9mzZ+XYsWOybt06+eWXX+TIkSMp/s5PPvlE8uXLJ//5z3/MfVKjYaB27dqpltu1a5f07ds3xTIff/yxbN26VYYPHy5ptXHjRlPvBx98MMVy77zzjpQtW9Zz+fz587J9+3b57rvvZPPmzX4/Xnql9blHRkZK69atpUaNGpI7d26Ji4szz+OHH35I9bXOzLpWqVJF1qxZI3feeacsX75c2rVrJw888ECq97ty5Yp07NjR59fL3+Py1ltvSadOneRf//qXXLp0yefnA6SGFh7ADxpcHn74YQkNTfqj06pVq2v+O3Xf58cff5Tp06fLokWL5OTJk/Lvf/9b9u3bZ76kbrjhhiQfT4OL/geuX0RPP/20T3VcuXKlTJs2zXPauXOn+f1nzpzxun7+/PmpPlbLli09Ye160+OmJ3f9Vq1aZX5/bGysPP7445LZ0vLcNQjv3r1bevfuLYcPH5a5c+ean507d5a9e/ean1mlru+99578/vvvJuyoTZs2eb0/9H2q75u8efN6Xa/vYX9fL3+Oy7BhwyQmJkaeeOKJDDk2QEL6byonjgHvAR/eAxMnTnSpsLCwJG/fu3eva+nSpT7f54EHHnBdunTJNWXKlCQfb/To0eYxP/zwQ9eJEydcN954o9+vU9OmTc3v79atm9/33blzp6l/ej4fGzdudH333XepltPjps814XURERGurVu3uk6ePOnKnj27X4+X3pO/z71du3bmOA8bNizJ27t37+56/fXXs0Rdixcv7rp8+bLrscceS7ZMTEyMeT7Dhw9P1+uVluMyefJkV2xs7HV/jTmJo45BNq/oAyBTTZkyRe666y555plnpH79+ua/ardcuXLJQw89JO+//76MHz9enn/+eWnfvr18+eWXGfK7S5UqZbomSpcubVp/tMVHuxfcXXUTJ06Um266SerUqWPOJ+4Ge+ONN6RixYqebg7tlpg3b57MmDFDMsrFixfNYz711FNSvnx5+fvvv5Ms52tdPvvsM1m7dq2MHTvWtCBo94qWHT16tOkSckvtuScWHh4uH330kelue/HFF5Mso2NToqKi/HoN3F1B2sVTqVIlM8ZFu/O++uorUz4tdVX6vgoLC8vQ1yqp10uPR1qOi7aGapeldrtpixGQEejSAgJswoQJnu6wxN0A2bNnN1/G+gU2e/ZsefLJJzPkd+pYig0bNpiQtWzZMjPu6IsvvpDffvtNIiIiTBntptDxRvv370+yG+yPP/7wXD9nzhy5fPmyfP311/L5559LRtLgp86dO5dsGV/ros9bu34mTZok0dHRpjunQYMGpjumZMmSnnKpPffE9DhqN8w333wjV69eTbbcqVOn/HoN8ufPbwJaly5dTGhYvXq1lCtXzoy9cR8Xf+uq9Dlv2bJFjh8/Lhkt4euVluOili5dan42bNgww+sHZwt4MxMnjkGwvAfc3VOTJk0y5xOf4uPj/erS0lOePHnM7TNmzPC6fsWKFaZp3325RYsWplzFihXT1aWlv0+7HH755RdXSEiIp1y9evVMuf79+6e5q6R169bmMapWrZohXVrlypVznTp1yrVp0ya/Hy+puhw8eNB15swZV61atTzXRUVFuU6fPu0aMWKE1/39ee7PPfec+V36O30p7+tr0LlzZ3M5Ojra6/758+d3hYeHp/l10vKzZs1KsUxaurQSv17+Hhf3SY/JlStXXKNGjfLrfpw4BpLCMaBLC0gDHbiZ1H+saZlO6265uPHGGz3X3XLLLVKzZk155ZVXPNfNmjXLDEDWrpjkugd80aJFC9OFoINDE3ad6ADWFStWmJal/v37p/o42r2ig1S1S65gwYKSLVs2z3OoWrVqst1PKdHZaO5uGW3d0BlE+py1Cyaj6qJdQu6Buu7WBX3e1apVk7TKmTNnqq1QaXkNtItI6XPTlj43neWXHgUKFMiQ1p3UXi9/j4ubHpMTJ06YrjogoxB4gDSYPHmyGSuS1BoxafnSUNql4aZdV/r43bp1Myc3DVk6nuPVV1/1fBn6S8eNKO3SSEynE+vMnNRowPj555/l9ttvlzFjxpgulPj4ePNFev/995tpx2mhX4zaJeOe5vzSSy+lGpz8rYtOhU5Mx/FowEyro0ePer70M/I10CneGh60a05nVS1cuNDMcNIuucTdQP7Q94672yw9Unu9/D0uCWl3blrf40BSCDxAgOkXtdJxJEqnqOt/+EOHDvVc56ZfLvrl16ZNG/n222/T9Pvca5skNRVeW0V8WfukWbNm0rRpU2nbtq1MnTrVc32tWrUkvV+g/j4vf+uS1Jeotigkt9SAL9xjTnQZAR2vklGvgf7UsV06bqdRo0ZSr149GTx4sLz77rtmLFJS4c0Xhw4dSlMI8ff18ve4JAw72jqk9QQyCoOWgQDThQIvXLjg+ULQ2SnaKqGzs/TLJPFJ/8NPz+Dlv/76yytouekX/q233uq5Xeng36SCQLFixcxPHVCbeDBsZrtedUnuuSdFZxItXrxYOnTokGw3jPv4+vsauFuCdIaZBmENctpt99hjj6WprkqDdOXKleV68/e4JOzSVdq9B2QUAg8QIPoFMG7cODMTRaec6wJsSsOMzsJJblVe7b7R+9x8881p+r2//vqrrF+/Xl577TUpUqSI53rtJtOuFm1ZctOFEYsXL37NY7jDhY4tcdMpxDrzKLNdr7ok99yTo4vnaTfkTz/9ZKaZJ1S0aFEz1dpdR19fA225cn/5J2z9SNwF6m9ddSaYvv/KlCkj15s/x8VNW6/0PjrFHcgodGkBmTj9XLtO9AtLp+rqF5lOR9auCvcfdu260G4LHa+RHA08+l+xrtSsX5j+0nFA+gWj45D0S1froF+6+uWnYzB0baCEWxZoOZ32rYHMvb6LDvrV8UravaJbEmgLg67I++yzz3qtJZQZrlddknvuydm2bZtZ10cHIut08z///NMEEZ3+rq0y+ji6tIA/r4FON9cuTB3grK082gWm6+1oa6CuX5PWun7//ffmPjpWKKX3Wkbw57i46bglHaRPlxYyEntpAX7QsQglSpRIdtyCfonpl5R2OyW+j9LAo+Me3HtpJR54qv8B65eDfgnouirJ0dYLXXhO/1NPjX6xaPeObjmxY8cOr9t0BpO2FOkgX+0+0C0vEtMvYu1y0LElOnNG17lx0/vqgn8640fHa+hAWB1zouvF6Beduvfee83jLlmyJMV6avDT35HaYnjJPZ4vddFBzPolmrirRF8jHeQ8c+ZMn597SjRwVa9e3XRN6hYKOtZGfybFl9dA3xcVKlQwA4M1NBw8ePCaMv7WVbtMddyThuykZhxquNLjp0FLQ0paXy9/j4vuoaXPsXHjxl6fIyC9CDwA4EB58uQxQVD3t9Ku1axCZ6Dp6tI6dR/ISHRpAYADaSuQznBLuP5ToOkSA9rd5p7dBWQkWngAAID1mKUFAACsR+ABAADWI/AAAADrEXgAAID1mKWVaB2L06dPB+7VAAAAftOlDA4cOJBiGQJPgrCT0kJvAAAg69IV7FMKPQSe/5+7ZUcPGK08AAAET+uONlik9t1N4ElEDxiBBwAAuzBoGQAAWI/AAwAArEfgAQAA1iPwAAAA6xF4AACA9Qg8AADAegQeAABgPQIPAACwHoEHAABYj8ADAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB62QJdAQTeVdeMQFcBmSg0pCXHG4Dj0MIDAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANZjawkAsBhbxzgLW8ckjxYeAABgPQIPAACwHoEHAABYj8ADAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAYD0CDwAAsB6BBwAAWI/AAwAArEfgAQAA1iPwAAAA6xF4AACA9Qg8AADAegQeAABgPQIPAACwHoEHAABYj8ADAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANbLUoEne/bsEhYWluztISEhqT6GL2UAAICzZJnAM3ToUDl//rx8+OGH19z26quvyqFDh+TSpUvy999/S8OGDdNUBgAAOFOWCDwtWrSQxo0by6ZNm665rVu3btKvXz/p0KGD5M6dW3744QeZOXOmlCxZ0q8yAADAuQIeeIoUKSKjRo0yYUVbeBJ78cUXZcyYMTJ37lyJj4+X/v37y9GjR6V79+5+lQEAAM4V0MCj422+/vprGTJkiOmGSixfvnxSrlw5Wbhwodf1erlOnTo+lwEAAM4W0MDzxhtvyJUrV0zgSUp0dLT5eeTIEa/r4+LiPLf5UiYpEREREhkZ6XUCAAB2CljgqVWrlvTq1cuMv9HZWXrSFh+dpaXnvSoZGnrNZZfL5XeZhPr27SunTp3ynPbv358hzwsAAGQ9AQs81apVk1y5csn69evlxIkT5lSlShXp0aOHOa+B5eDBg6ZswYIFve6rl3VGlvKlTFIGDBggUVFRnlNMTMx1eJYAAMDRgUcHKufIkcPrpON4RowYYc5fvXrVBB8NRAmnmGsrkF5evHixuexLmaRcvHhRTp8+7XUCAAB2CvgsrdQMGjRIunbtKm3btpXChQub8T7aMvTZZ5/5VQYAADhXNslCLly4YBYOTGj8+PEmvGgXlA5Cjo2NlSZNmniNufGlDAAAcC7dhyH5kb0OorO0dPCyjudxWvfWVdeMQFcBmSg0pCXH20H4fDuLEz/fkT5+f2f5Li0AAID0IvAAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAYD0CDwAAsB6BBwAAWI/AAwAArEfgAQAA1iPwAAAA6xF4AACA9Qg8AADAegQeAABgPQIPAACwHoEHAABYj8ADAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAYD0CDwAAsB6BBwAAWI/AAwAArEfgAQAA1iPwAAAA6xF4AACA9Qg8AADAegQeAABgPQIPAACwHoEHAABYj8ADAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAYD0CDwAAsB6BBwAAWC9boCtQr149adq0qeTKlUvWr18vEyZMkLNnz3qVKVGihHTp0kWio6MlNjZWxowZIxcuXPC7DAAAcKaAtvB8+umn0q9fPzlx4oTs2rVLunfvLn/++afkzZvXU6ZSpUqydu1aqVixomzdutWUWbBggWTLls2vMgAAwLlCRMTl750aNWokc+fOTfcvL1asmOzdu9dzOSoqSo4dOyadO3c2LT1q5syZEhERIffcc4+5XLBgQdm9e7c8/fTTMnbsWJ/LpCYyMlJOnTpl6nD69GlxkquuGYGuAjJRaEhLjreD8Pl2Fid+viN9/P5OUwvPL7/8IhkhYdhxBxVtlTlw4IC5HB4eLk2aNJFvv/3WUyYuLk7mzZsnLVu29LkMAABwtjT1+ezcuVPKly8vmzdvTncFKleuLL179zbJ7NZbb5UePXrI/PnzzW3Fixc3LTfa3ZWQXtaxP76WSYreJ3v27F4JEQAA2ClNLTz//e9/Zdy4cXLHHXeY8TY5c+b0Ovnjn3/+MeNtlixZYsbydOjQQfLkyWNuy5Ejh/kZHx/vdR9tsnLf5kuZpPTt29c0gblP+/fv96veAADA8sDzxRdfSK1ateSPP/4wgeXMmTNeJ39o95WGp8GDB5sAVapUKXn++efNbRpElDsAueXLl09Onjzpc5mkDBgwwLQquU8xMTF+1RsAAFjepVW7du2Mr4mImY6+fft2KV26tGeMj7b66CyshOOGtBts3bp1PpdJysWLF80JAADYL02BZ/ny5en+xTqGpnHjxjJr1izPdTqt/LbbbpNJkyaZyy6XywxG7tq1q4wcOdJ0W91+++2mdal///4+lwEAAM6WpmnpGSEsLEwmTpwoFSpUkI0bN5ouqTvvvFO+/vpr6dmzp1y5csWU0zFCv/32m/mpCwo2aNDAdKm5u718LZMapqXDKZw4bdXJmJbuLE78fEf6OC09zYGnY8eO8uCDD5pZUokX+KtSpYrPj3PzzTdLtWrVTMuMhhX3lPTE4ah+/fqeVZR1Rea0lEkJgQdO4cQ/iE5G4HEWJ36+I30MPGnq0nrppZfkxRdflFGjRsn9998vr776qulGat26tVk92R87duwwp5Roa497qnp6ygAAAGdK0yytp556yrTuvP322+byoEGDpF27dqYLSWdZAQAABH3g0VDjHrh87tw5s/Gn0unl2q0EAACQlaQp8OiYncuXL5vze/bskZo1a5rzOp7n0qVLGVtDAACAdEr3duK6OadOC9fNRLV154cffkjvQwIAAAQ+8BQoUMBz/v3335dDhw5JnTp1zHl/By0DAABkycBz7Ngxr8tfffWVOQEAAFgzhkeFh4ebLqzOnTt7ritYsGBG1QsAACCwgUcHJ//1119mWwhd0djtk08+MevyAAAABH3gGTZsmCxcuFBy587tdf2HH35oFiEEAAAI+jE82pVVrlw5z35Xbro7efXq1TOqbgAAAIFr4dGdzt2uXr3qOR8TE2P2xAIAAAj6wLNgwQKzo7lyuf5v79GcOXPK4MGDza7lAAAAQd+l1bt3b1m0aJG0aNFCQkJCzGKDd9xxh1l9WX8CAAAEfQvP1q1bpXLlyjJ9+nSZOnWquW748OFyyy23yK5duzK6jgAAAJnfwqMDk//8808ZOHBg+n47AABAVm3hWbNmjQk8vXr1krx582Z8rQAAAAIdeMqWLSs///yz9OnTRw4cOCCTJk2Se+65x4znAQAAsCLwbNu2Tfr162dWXG7Xrp1ky5ZNZsyYYcbvvPPOO1KqVKmMrykAAEBm76XlXoNHt5fo1KmTWWE5Ojpa3njjDROIdOZW0aJF0/PwAAAAgQ88tWrVklGjRsnBgwflxRdflA8++MC07tSuXdtsLjpt2rSMqSUAAEAg1uHp2rWrGcujLTwdO3Y0P92rLmvX1oMPPihnzpxJT90AAAACF3i6d+8uY8eONTulHzp0KMky58+fl3//+9/prR8AAEDmBp6CBQtKXFycadnxxbhx49JaLwAAgMCM4dm3b58sW7ZMXn/9dalWrVrG1QIAACCrBJ4iRYrIp59+KlWrVjUbiO7du1dGjhwp9913n+TIkeP61RIAACCzAs/Ro0flq6++kvbt20uBAgXk8ccfl7Nnz5pd0o8dOyYzZ84043uYjg4AAKyYlq47o8+bN89MRy9fvrzZOFQvaxjavn27/PXXXxlbUwAAgMycpZXcDupDhgwxp6ioKGnWrFlGPTQAAEDmB55y5cpJ3bp1zcrKun+WTk1fsmSJbNmyxdx+6tQpmTx5cvpqBgAAEIjAkzt3bhk/fry0bNnSLDJ48uRJcblckidPHgkNDTX7aekihBp4AAAAgnIMz8cffywlSpQwO6Nnz55d8uXLJ/nz5zfnmzZtam7TMgAAAEHbwtOqVSupUaOG2Rw08QDmOXPmyM6dO2XFihUZXUcAAIDMa+HRbqtLly4le/vFixclLCwsfTUCAAAIZODRDUInTJggt9566zW3Va9e3dymZQAAAII28PTq1csMVl69erUZsKxdW3rS82vWrDG3PfPMM9evtgAAANd7DM+RI0ekfv36UqtWLTMtvVChQuZ697T05cuXp6UOAAAAWW8dHg02hBsAAODohQcBAACyEhYeBAAA1mPhQQAAYD0WHgQAANZj4UEAAGA9Fh4EAADWY+FBAABgPRYeBAAA1mPhQQAAYD0WHgQAANZj4UEAAGA9Fh4EAADWY+FBAABgPRYeBAAA1mPhQQAAYD0WHgQAANZj4UEAAGA9Fh4EAADW86tLyxclSpTI6IcEAADIWoFn165dGf2QAAAAWSvwAAAABPUYnp07d16/mgAAAGSFwJM/f3759NNP5fTp08mWee+99zKiXgAAAIEJPN98840ZozNy5MhkyxB4AABAUI/h+eyzz6RDhw4pllmwYEF66wQAABC4wLN27VqpV69eimUaNmzoXwVCQ6VChQpSpkwZCQsLS7Zc0aJF5bbbbpPIyMh0lQEAAM4T0Fla/fr1k/3798v3338vc+bMMd1lLVq08CqTPXt2mTJlimzevFnGjx8vhw4dkmeeecbvMgAAwLkyJPBoi8rtt98uUVFRvv/i0FDJkSOHVKxYUSpVqiQ333yzjB49Wr799luJjo72lHvrrbfMY5cuXdqUffTRR2X48OHmOn/KAAAA5wpNy0rK7777rueydkVt3bpVli9fbqat16hRw6fHuXr1qrzxxhty/PhxrzFCOXPmlFtvvdVzXZcuXUwQ0lYbNX36dImNjTXX+1MGAAA4l9+B5/3335cNGzZ4Lvft29d0R2krj05ZT88srZo1a5qf27dvNz8LFy4shQoVktWrV3uVW7FihVSvXt3nMkmJiIgwdU54AgAADg88d911lznde++9cu7cOc/lJk2ayNKlS81g4VWrVpluJPdt/q7xo91Q2qW1ZcsWc12+fPnMz2PHjnmV1cvu23wpkxQNaqdOnfKcdCwRAABw+Do81apVMz/Dw8PNrCoNPQUKFDChQltL9Hb9qeNy3GUXLlzo02Pr2J9ffvnFdEk98cQTnusvXbpkft5www1e5fV3XLx40ecySRkwYIAMGTLEc1lbeAg9AAA4PPB89NFH5ufDDz8s8fHxpjVGBwsvWrTIc1uVKlXkoYce8lz2hQYN7RK7cuWKNGvWTM6cOeO5be/eveb6mJgYr/vo5T179vhcJikahlIKRAAAwMFjeHSg8cCBA+XChQvy8ssvyzvvvOO5TQcJjx071u+wo+655x7TtZSQtiItWbJE7r//fs91N954ozRu3Fh+/fVXn8sAAABnCxERl7930oHCVatWNTOhDhw44Lle19DRAOPuZkpJtmzZzKrMOsura9eucvLkSc9tOusrLi7OnK9fv74JLoMHDzZjhXr16iWlSpUy3Wba0uRrGV/ClwYu7V5Laa8wG111zQh0FZCJQkNacrwdhM+3szjx8x3p4/d3mgJPRtCK/fTTT0nepi1ICW+rW7euPP3002Z9Hg1Zevvhw4e97uNLmZQQeOAUTvyD6GQEHmdx4uc7MqsHnqyGwAOncOIfRCcj8DiLEz/fkT4GnoBuLQEAAJAZCDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAYD0CDwAAsB6BBwAAWI/AAwAArEfgAQAA1iPwAAAA6xF4AACA9Qg8AADAegQeAABgPQIPAACwHoEHAABYj8ADAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAYD0CDwAAsB6BBwAAWI/AAwAArEfgAQAA1iPwAAAA6xF4AACA9Qg8AADAegQeAABgPQIPAACwHoEHAABYj8ADAACsR+ABAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAYD0CDwAAsB6BBwAAWI/AAwAArEfgAQAA1gt44GnatKlMnTpVNm7cKDVr1kyyTPPmzeWXX36RP//8U7766ispVapUmsoAAABnCmjgGTRokLzwwgsye/ZsqVChgtx4443XlLn33ntl2rRp8uuvv8rTTz8tOXLkkN9//13y5MnjVxkAAOBcISLiCtQvj4iIkIsXL0pMTIzs27dPGjRoIAsXLvQqs3z5ctP607lzZ3M5PDxcDh06JB988IEMHDjQ5zKpiYyMlFOnTklUVJScPn1anOSqa0agq4BMFBrSkuPtIHy+ncWJn+9IH7+/s0kAadhJSc6cOaVGjRoydOhQz3WXLl2S3377TRo2bGjCjC9lACRPW1YLFCggISH6/w+ClcvlkqNHj8rZs2cDXRUgSwpo4ElN0aJFJTQ0VA4ePOh1vbbeVK5c2ecyybUuZc+e3SshAk6iAadLly6mZRX2WLBggXzxxRcmAAEIksATFhaWZEvQhQsXJFu2bD6XSUrfvn2lf//+16HWQHDQsHPXXXfJt99+K5s2bZLLly8HukpIB/17p2Mh27dvby6PHTuW4wkES+A5duyY+anN7QnpZfdtvpRJyoABA2TIkCFeLTz79+/P0PoDWZV2BWvLjoadn376KdDVQQbZvn27+fnQQw/JpEmT6N4CstK09JQcPnxY9u7dK7Vr1/a6vk6dOrJq1SqfyyRFW4R0cFPCE+AU+fPnNz+1ZQd2cb+mif8JBJwuSwceNWrUKHniiSekTJkynmZ4Pf/555/7VQbA/+MeoEw3ln3crymD0IEs1KXVunVr07XkHmujCwbqDIMRI0bIJ598Yq7TWVbFixeXdevWycmTJ01ZnX4eGxvreRxfygAAAOcKaOCZN2+eCT2J6dRKtytXrki3bt3kpZdeMs3wul5P4v9KfSkDIPjlypXLTKOPi4vL0MfVmZ7FihUz4/j42wHYKaCBRxcK0pMvfBlnw1gcwE4dOnSQPn36mK7qEydOmOCjK7TrTMv169en+/Fvuukm2bVrl1nKIiMeD0DWk+XH8ABwtjfeeENGjhxpVk7PnTu3FClSRAoWLCjjx483e/ElFV60XEprcOXLl8/rOm3dUfrYJUqUkOjo6BTLAwg+BB4AWVbp0qXlzTffNC05GnB0FXV1/vx5+fHHH72WltA1hTZv3mymZuvsTd2mpmTJkp7bb7jhBpk8ebIZ57dhwwbToqNd6tqd9cMPP5gyumCfLtw3fPjwZMsDCE4EHgBZlgYMnYSgMzFTohsFa2j5/vvvzXkdy3fu3DmZMGGCp0z37t2lSpUqphWnUKFCZukK7cK6evWq1KxZ05TRFqNSpUqZxfuSKw8gOBF4AGRZ2kKjrTVnzpxJdYyPtv5oa5AGmPj4eHnuueekbt26ctttt5ky2i2li5HqGCCl29G89957yT6mv+UBZG0EHgBZls6Y0q6l1JQrV850OyWcYaXdW9rKU7ZsWXN59OjRZuzPtm3bTJfV/fffb7qzkuNveQBZG59eAFmWzpjSAcgxMTEpltMxPQk3A1YaTrQ7TG9Te/bsMXtNPfbYY2Za++DBg+X333/37MeXmL/lAWRtBB4AWdaUKVPMoGGdqZUUd/j466+/pGrVql6zs+68805zu3sBUg1A2t21ePFieffdd6VFixamy0tbh3SzYZVww+GUygMIPll681AAzqbjZzp16mQ2OdUworOojhw5Ysb2NGvWzAQaHaujs6lee+01s2GmjuPR4PPpp5+amV3uDTV1RpeOBZo1a5Z53CeffNI8ls6+0q4vbcVp06aNWRtMV3zv27dvsuUBBB9aeABkaTNmzJBq1aqZrqmPPvpIpk2bZkKOBplXXnnFs9p648aNzUbCX375pbz//vsm/Dz11FOex3EHmEGDBpnbdL2ehg0bmrCjHn/8cbOD/Jw5c8yYndTKAwguuoOgK9CVyAoiIyPNf3ZRUVGO2zn9qmtGoKuATBQa0tIsrqfdNNpVtHv3bo6/RRK/tny+nff5dppIH7+/aeEBAADWI/AAAADrEXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8ABAIkWKFJGNGzdKsWLFssTjAEg/Ng8F4GVw7NJMOyK9q9TJkkc/PDxcKlSoIBEREeayBhbdY6tRo0Zy4MCBND8OgMChhQcAEtm/f78JKu59xjSw6GUNMACCE4EHQFDJlSuXvP3227J48WL5/fffzc7pISEhnhYV7ULSU2xsrNlpvW3btl73L1OmjLlddz6fOHGirF692uyGXqpUKU+ZggULml3ZCxcubH7f7NmzzfVz58419/3f//7n0+8CkHXQpQUgaGhLy/z5803Aeeutt+T48ePywAMPSIcOHeTrr7+WS5cuSevWrU1ZDSQ1atSQMWPGiMvlkqlTp5rrs2fPblprNOS88MILsnPnTnn55ZfN4+r158+f9+qKio+Plx49epguraeeesq0/pw5c8an3wUg6yDwAAgaHTt2lPLly8vNN98sR48eNdctWbJEwsLCPGU2b97sOb9u3TopWrSoCSqJQ4gGpm+++cacf/TRR2XPnj3y+OOPy6hRo7zKaYDZsWOHOb99+3ZPN5c/vwtA4BF4AASNO+64Q1auXOkJO25XrlzxnG/SpIl069ZNSpYsKTlz5pTcuXPLqVOnrnmshQsXes5rq87y5culevXqftXH198FIPAYwwMgaGh31NmzZ5O9vX79+jJ9+nTT6tOzZ09p06aNGW+j90tMQ05C+rg5cuTwuS7+/C4AgUcLD4CgsWnTJnnyySclNDRUrl69es3tzZs3N2NxhgwZ4rkuf/78ST5WpUqVzPgdt8qVK5txPUlxtyC5B0f7+7sABB4tPACCxpdffil58uSRQYMGecbt1KtXz3QtqcOHD5sgky9fPnP5zjvvlK5duyb5WG+++aZ5LKXdUqVLl5Zx48YlWVYfVwNWwplc/vwuAIFHCw+AoLFv3z7TsqJdR9qNdPr0admwYYM89thj5nYdcKy3792718zg0gHH2u1Up861CxwuWLDAtPBcvHhRbrjhBnniiSfMwOWknDt3ToYOHSozZ840ddDxP88//7zPvwtA4BF4AATF6sduuv6OtqzoGjk6DkfDRsJxONraU6BAATMeR8NIVFSUuZzY4MGDpU+fPmZmVVxcnFy4cCHZhQfVSy+9JP3795dChQqZAOTL70rqcQAEBoEHQFA6ePBgsrclnMWls6aSmzmlrTIaVBK7fPmy15RzN11/Z9u2bT7/ruQeB0DmYwwPAACwHi08kKHrrm3uB2y1ZcsW08105MiRQFcFQCYi8ABwFN0Sgm4mwHno0gIAANYj8AAAAOsReAAAgPUYwwMAFmNSAvB/aOEBAADWI/AAQCbImzev2Z6CDUaBwCDwAEAG01Cj4UZDjptuO6H7b7k3LAWQuRjDA8DLVdeMTDsioSEtrTz6Gmo03AwbNsyz19c///xjrmPBQyAwCDwAgk6rVq2kVq1aZgPPH3/8Uf7++2/PbdHR0fLqq6/KgAED5N5775Vy5crJ1q1bZfz48XLlyhWvx7njjjukcePGcvXqVbMp6bx58655nP/+97/Spk0bKVOmjHz11VeyceNG+fDDDz17Ze3atUt++OEHz95euvP6a6+9Zs6/+eabZm8tvc93330nJUuWlPDwcK/Hf++990w9y5cvb3Zv13rq4ohu2bJlk06dOpnfr8/jp59+kn79+snAgQPl8OHD1/lIA/agSwtAUPn222/l008/NSGlePHismrVKunQoYPndt2tXFtSli5dKo0aNTKhRHc5nzHDu+VqyJAhMnHiRImIiJCwsDAZO3asfPzxx9c8jgYhDVcaaDRg6YajGnL0pIGjXr16smHDBrODu9J66S7pat++fZ5yibu03I//xx9/SP369c1u7RqApk6d6lVPDThvvfWWCWsNGjSQZcuWmfsltQM8gOTRwgMgaNxzzz3Stm1bEy50Tyylu5freJlp06ZJfHy8p6xe7t27tzk/ZswY0zrSokULEyAaNmwoXbp0Ma0qcXFxnjL6WKNHj/ZqMdLrBw0a5FWPjz76yOvyqFGjTKuLBq+LFy/Kl19+Ka+//roJUbt37zZlSpQokeRzGjFihHzyySfmvNZtzZo1Jsjt2bNHmjdvbkJO2bJlzWWldXnllVcy5HgCTkLgARA0tPtp+fLlnrCjvvjiCxMCqlatalp13L755hvPeQ0Lv//+u2nx0VChXWLa1fTyyy9LSEiIOalz587Jbbfd5hV4tMsssdy5c8uDDz5ouqhy5swppUuXTnOLy6xZszzn169fb34WK1bM1Pnuu+82LUzusON+XgQewH8EHgBBo1ChQp4WGbejR4+a7h69LaHEg4P1fjpuRhUsWFBOnjxpupwS0q6jP//80+s6HWyckIacFStWyF9//WW6o/T3Fy5c2ISetNBuMjf3GCMdt+OuZ+LnwaBnIG0IPACCxt69e6VJkyZe18XExJgxOHpb4usTtowULVrUjH9ROh6nevXq13RN+UIHEGvXl3avuekYIR3n46bjfDLCgQMH5M4777zmeQHwH4OWAQQN7V7SLqeE4aJXr15mYHDCbijVo0cPz/lbbrlF6tat6xm4rAOfdfaWhpeEatas6bV2TlJ0lpUGLDcdhNy5c2evMidOnPB0faXHzJkzpXbt2qa7zu2pp55K12MCTkULD4CgoeN3dIDynDlzTPi56aabTAuIDmTWwcIJ6YDkhQsXmqne999/v5lSruN4lHZJ6Uynzz//XDp27GgGFlesWNGM5dGBzSnRAclPP/20LFiwwNPSowEnMjLSqxtM66qDlnUMjo7NmT17tt/PV7vMdJq6/i4NazqY+cYbb/TMBgPgOwIPgKBaDPCll14yIcC9Ds9jjz12zbge1bp1axN6dIbTuHHjZP78+V63Dx8+XKZMmWJmbOXIkcPMxtKQ4qbdXhqKdHBzQjt27JAKFSpI06ZNzf20W0zH3iRsdVL6uDrLSsf36LT0xAsPJvX4+jh6nQYpN51Npo+lz0PDlj6Ojh86duxYBhxNwDkIPACCztq1a80pJdoCoi0jekqOho6Es7kS0mCR3BgfDS1ff/2113W6Fk9COuPr+++/97ou4eMl9/iJr6tWrZoJa+7ApkFt8+bNSYY8AMkj8ABAFvbwww/LyJEjzRilypUrmxWX27dvH+hqAUGHwAPAKsl1RQUrXX1ZZ5TpSQcx67iexFPlAaSOwAPAKil1RQUrXRso8fpAAPzDtHQAAGA9Ag8AALAegQdwIPcaLtmzZw90VZDB3K+pe5sKAP+HMTyAQwf2nj9/Xrp37y6TJ082U5z5ggxuuvqz7r2lM7j0tT106FCgqwRkKQQewIEuX74sr732mjz55JPSs2fPQFcHGWjTpk0yYMAA8xoD+H8IPIBD6eJ5+sWo+z1FRUWZbRUQvHTDUp2Kr7vAZ9TmpYBNrAk8usS77oETHR0tsbGxsmjRokBXCcjy9ItR94Fyb3YJALayYtByoUKFzDLz2kSvOyl/9913Zq8dAAAAa1p4Bg0aJKdPn5Y6deqYHZMrVapkApBuDDh9+vRAVw8AAARY0LfwhIaGStu2bc1uyBp21Pr1683y6+w3AwAArGjhKVasmOTKlcvsHpx4psLtt9+e7P0iIiK81iCJjIz0+ukkEaFhga4CMpET3+NOxufbWZz4+Y708Tlns+WJJh50qZdTOgh9+/aV/v37X3P9/v37r0MtgazjGUs21QRwLSd/viMjI83wFmsDz9mzZ81PnVabkE61jY+PT/Z+Oh13yJAhXtfly5ePXYgd9MHQcBsTE5PiBwRA8OHz7czX/MCBAymWCfrAs3v3brOqaOnSpeXXX3/1XK+Xt27dmuz9dLyPe8yPG198zqOvOa87YCc+385x2od/XIN+0LIuh//TTz9Jhw4dPAunlShRQu666y6ZOnVqoKsHAACyAE0IQb8k58033yxLliwxCw6uWLFCHn74YdO607x5c88miUDi5k9dlVa7QmnhAezC5xtWtvCoHTt2SOXKleXHH380K8f269ePsIMUXbhwwQxa158A7MLnG9a28AAAAFjfwgMAAJASAg8AALAegQcAAFiPwAMAAKwX9AsPAr6qVKmSdO3aVYoXLy7Zsnm/9b/44gszyw9AcOLzjdQQeOAI5cuXl1WrVsnKlStl3bp1ZsHKhM6cOROwugFIHz7f8AWBB47QqlUrmTZtmjzyyCOBrgqADMbnG75gDA8cQVfc3rRpU6CrAeA64PMNXxB44Ahz5841q28nHrsDIPjx+YYv+OsPRyhUqJDkz59f/v77b/ntt98kPj7e63bdgPaPP/4IWP0A+Ofee++V+vXrey7z+UZqCDxwhKJFi8rOnTvN+X/961/X3L569eoA1ApAej7TNWrU8Fzm843UsJcWAACwHmN4AABBT9fXypcvnzkfFhYmvXr1koEDB0qZMmUCXTVkEbTwwDFCQ0PNwoONGzeWwoULy759+2TGjBkyadKkQFcNQDoUKFBA5s+fb8b0HD9+XPr16ycvvPCCbNmyRUqVKiWlS5eWc+fOcYwdjhYeOIL+x6d/EIcMGWKmsOqYnYiICBk7dqx8//33ga4egHRo166d+Xxr2FGdOnUya27dcccdsnHjRmnWrBnHFwxahnP+IMbExJj/9I4cOeK5Xv/7W7ZsmfnPcNGiRQGtI4C0KVKkiOdzra23+lnXAKQ08OgsTYAWHjhC1apVZeLEiV5hxz2zQ7u19HYAwWnz5s3SunVrE2yeffZZE3bc28eUK1fO3A4QeOAI2tStf/iSotf/888/mV4nABljypQpZozOwYMHpUePHvLee++Z6ytUqCDR0dGyYMECDjUYtAxnKFGihGnaHjNmjIwbN07i4uLMOh49e/Y0/ftly5b19P8DCE4lS5aUo0ePejYD1s94SEiI7N27N9BVQxbh4sQxcMJ7oH79+q7Y2FhXQsuWLXNVr1494HXjxDHgPcB7gPeAXNdjwLR0OI4OanRPS9eWHgB20DE82o2VO3dur+vXrVsn27dvD1i9kHWQKjkGvAd4D/Ae4D0Q1O+B999/33Xp0iVzunDhgqcV9/z5865evXoFvH6cJODHgBYeWKtVq1ZmkcGpU6dKZGSkOZ8cLTNv3rxMrR+AjNGgQQP55ptvzGe8S5cucujQIRk9erQ8//zz8uijj5pZmBcuXOBwOxybh8JaefLkMYMWc+XK5TmfHC0DIDjVrl1bxo8fLxs2bBCXyyXh4eFy8uRJefvtt6Vu3bpmZ/Vp06YFupoIMAIPrKWzsfTkXnr+xx9/THImlt7mXrMDQPDJnz+/adVROktLFyJ007E7uhAhwDo8cIQ+ffqYfbT8vQ1AcFmxYoU88MADUqtWLdPy06ZNG9m2bVugq4UsgBYeOJ52Z7nX7QAQfJYuXWq6sJQuMjhr1ixZsmSJ2TB4woQJMnv27EBXEVkAg5ZhtZYtW8rdd98t9erVk/j4eFmzZo3X7Tp9Vf8bbNSokaxcuTJg9QSQsXSigo7lYRV1uNHCA6vp+JwyZcqYQcs5cuQw5910cOOJEyekW7duhB3AMqdPnw50FZDF0MIDR2jfvr1p8qZpG7Br2QlfsOwEFC08cITJkycHugoAMlBqS00kxLITULTwwFFYeh4AnCvgyz1z4hiw9DzvAf4O8B7w9z1QokQJV5EiRXjv8N5x+XIMWIcHjll6vmPHjnLLLbfIsGHDpF+/fqZJvH///rJ792753//+F+gqAvDTM888I4888ojn8rPPPisdOnTgOCJJBB6I05ee37Vrl1l6HkBwK1asmOm2BpJC4IFjlp6Pi4vzLD2f8I8iS88DgP0IPHAclp4HAOdhWjocgaXnATv16NFD7rvvPnO+dOnScvHiRc9lt88++4ylKcC0dDgXS88Dwb+gqC/j7yZNmsSioyDwAAAA+9GlBWux9DwAwI3AA2ux9DwAwI2tJQAAgPWYlg4AAKxHlxasxRgeAIAbgQfWYgwP4ByhoaHStWtXady4sRQuXFj27dsnM2bMMFPSAcUYHgBAUAsLC5N58+ZJ9erVZebMmXLo0CGzr1aLFi3k559/lnbt2gW6isgCaOEBAAQ1DTQxMTFmpeUjR454ri9VqpQsW7ZM6tevL4sWLQpoHRF4BB5YP4Zn6tSpZlVlPZ8cLaP/IQIIPlWrVpWJEyd6hR21c+dO062ltxN4QOCB9WN4cuXKlep4Hi0DIDgdP35cbr/99iRvK1euHP/MwGAMDxyhQIECcuXKFfOH0Z/bAGR9JUqUkI0bN8qYMWNk3LhxEhcXZ/7B6dmzpzRr1kzKli3L5xuswwNn6NOnj5nB4e9tALK+3bt3m2DToEEDWblypbm8ePFiKVOmjDRp0oSwA4MuLTiedmedOXPG8ccBCGY6RqdKlSpmSrp7Wrq29ABuBB5YrWXLlnL33XdLvXr1JD4+/ppxPLlz55YHHnhAxo4dG7A6AkifXr16ScWKFWXBggXmtGbNGg4prkHggdV0fI42a+ug5Rw5cpjzbi6XS06cOCHdunUzzeAAgtPff/8tdevWlaFDh5rWnU2bNnnCj54OHz4c6CoiC2DQMhyhffv2cvLkSZk9e3agqwLgOipfvrwZy6Onhg0bSnR0tBm8/Nlnn3HcHY7NQ+EIkydPNrM48uXL51mZVZvBBw4c6NXqAyB4hYeHm1bdm266yZyioqJkx44dsn///kBXDVmEixPHwPb3QIECBVyxsbGuvHnzmsv9+vVzHTlyxLV48WLXgQMHXDly5Ah4HTlxDHgPpO090Lx5c9ecOXNcZ86ccW3fvt01ZswYV6dOnVxFixblmPK5ciU4BvyR4RjY/x7o1q2b6+OPP/Zc3rhxo6tx48bm/Ny5c11t2rQJeB05cQx4D6TtPfDBBx+41LRp01xt27Z15c+fn2PJ58mV+BjQpQVHKFKkiGfZeR3UqPvuzJ8/31zWrq5ChQoFuIYA0qp///5mHR79LL/88sty4MABWbt2rQwbNkxat25turYARRLmGFj/Hnj00Uddq1evdhUqVMg1YMAA1/Tp0z23aVP43XffHfA6cuIY8B7ImPdAzpw5XU8++aRr586dpuWnd+/eHFvh80Xg4U3giD8EERERrj/++MP88Ttx4oSrZs2a5voKFSq41q5d6woNDQ14HTlxDHgPpP09UKRIEfOPzeeff+7atm2b+azv27fPNWHCBFeNGjU4tsLni2npcJSSJUvK0aNHPSsr60KEISEhsnfv3kBXDYCfXnvtNdNVrV3Sb7/9tpmNtXDhQs/6O1u3buWYwoPAAwAISh988IEcOnRIfv31Vzl37hwBBylipWVYq1WrVtK4cWOZOnWqREZGmvPJ0TLz5s3L1PoByLiVloHUEHhgLd1OQrusdHNQ9/nkaBkAwads2bLSqFGjFMts2bKFbmsYDObiGPAe4D3Ae4D3QNCuv5MaZmkF/rXKCidaeAAAQes///mPfP755ymW+eeffzKtPsi6CDxwBN1J+fnnn5eaNWuaRcj0D+DSpUvNoMfY2NhAVw9AGh0/flx2797N8UOqCDyw3iOPPCLjx4+XDRs2yMyZM+XEiRNmg0EdxLxixQpp3ry5Z9VlAICdCDyw2g033CAjRoyQPn36yODBg71u0/V39LpRo0ZJuXLlAlZHAGmzfft2uqvgl4APJOLEMbhe74EWLVq4Vq1aleztusLynj17XNWrV+d9yPuQ9wDvAd4DYu8xYPNQWK1SpUoprq9z9epVszJr5cqVM7VeAIDMReCB1fLmzevZJT05cXFxphwAwF4EHlgtW7ZsphUnJXp7eHh4ptUJAJD5GLQM6/Xo0UPuu+++ZG8vXbq0fPTRR5laJwBA5iLwwGorV640U9BTsmvXLlm3bl2m1QkAkPnYLR0AAFiPMTwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AAAAOsReAAAgPUIPAAAwHoEHgAAILb7/wAiEaGpryXkhAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } ], - "text/plain": [ - "Utilities cooling heating\n", - "Distillation 60.192008 367.404722\n", - "Two Flash 47.028803 372.093536" + "source": [ + "# Compare total costs (capital costs and operating costs)\n", + "\n", + "two_flash_totcost = {\n", + " \"capital\": sum(two_flash_capcost[idx] for idx in two_flash_capcost),\n", + " \"operating\": value(m.fs.operating_cost) / 1e3,\n", + "}\n", + "distillation_totcost = {\n", + " \"capital\": sum(distillation_capcost[idx] for idx in distillation_capcost),\n", + " \"operating\": value(n.fs.operating_cost) / 1e3,\n", + "}\n", + "\n", + "two_flash_totdf = pd.DataFrame(\n", + " list(two_flash_totcost.items()), columns=[\"Costs\", \"Two Flash\"]\n", + ").set_index(\"Costs\")\n", + "distillation_totdf = pd.DataFrame(\n", + " list(distillation_totcost.items()), columns=[\"Costs\", \"Distillation\"]\n", + ").set_index(\"Costs\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "totcosts = two_flash_totdf.add(distillation_totdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(totcosts) # view dataframe before plotting\n", + "\n", + "totplot = totcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Total Plant Cost (TPC)\", ylabel=\"$1000/year\"\n", + ")" ] - }, - "metadata": {}, - "output_type": "display_data" }, { - "data": { - "image/png": "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EvLMz+Lq1au4evUqvv76a7i5ueHs2bMYN24c5syZ88ztIpIaT2MRyVDt2rWxfft2WFtb4+uvv9ZO9/b2xqlTp/DLL7/A399fpy1btgwAMHz48Kcue8GCBWjQoAG+//77EiP5durUCTNnzkRERITONUEAUKtWLYwdO7bE6/v37yM8PBwA8Msvv6Bp06b48MMPS92munXrPnPbi4qKIISAsbGxdpqDgwMGDRpUYt7s7OxnXqdUXkFBQXBzc9MZibh+/fplPqr05ZdfQqFQYPv27TA3Ny/R36lTJ22gPHz4MExMTDBhwgSdeaZMmYLi4mIEBARo1/9vly5dAgCYmZkB+PuzAFDi81AqlTqfJQBERESgqKhI+14ifccjO0Q1XJMmTbRfpBYWFmjTpg2GDBmCxo0bY/ny5di4cSMA4JVXXsELL7yAdevWlbqcxMREXLhwAd7e3li6dOkT17dr1y507twZkydPRps2bbBz505kZGSgU6dOGD16NNLS0vDuu++isLBQ530JCQmYOXMmmjdvjuvXr2PYsGHo2LEjPvzwQ+2827dvx9ChQ/H999+jR48eOHPmDIyNjeHk5IShQ4eib9++2mD0JIcOHcK0adMQGBiIXbt2wcbGBh9//DFu3rxZ4lEI4eHh6NWrF6ZMmYLExETcuXMH586de/oH/gxLly7F+++/jz///BNr165FdnY2/vOf/yAuLg7W1tbPPIISGhqKjz/+GN999x2io6Oxfft23LhxA0qlEh4eHhgwYAC++OILAMCBAwdw9OhRfP3112jevDkuX76MPn36YNCgQVi1ahVu374NAJg7dy66d++OQ4cOITY2FjY2Nhg/fjzi4+O1F1zfunULGRkZGDduHNRqNbKzsxEWFgYXFxesW7cOv/76K65fvw4TExPtkcF/B1oifSb5LWFsbGwVH1TwsaKiIvHw4UMREREhfvjhB9G5c2ededesWSOEEKJFixZPrGHu3LlCCCHat2//zHoHDBgggoKCRFpamsjNzRXXr18Xy5YtK/X25tIGFbxz544YP358iXlNTEzEp59+KiIiIkRubq5IS0sTf/31l5gzZ47OQIZC/D2oYGm1jRo1SsTExIjc3FwRGRkpfHx8xLx584T4O2lom6Ojozh+/LjIzs4WQpRtUMHStu3YsWM601xcXMSJEydEbm6uiIuLEzNnzhQTJkwQ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81FQUFDl20BERET6TW+u2TEyMsKwYcNgbm6O0NBQ7XRvb288ePAAERERWLRoEerUqaPtc3NzQ0REBO7fv6+dFhQUBCsrK7Rt2/aJ6zI1NYVSqdRpREREJE+SHtkBgHbt2iE0NBS1a9fGo0eP8PbbbyMqKgoAsGvXLsTGxiIxMRHOzs5YsmQJXnzxRQwePBgAoFKpShz1efxapVI9cZ2zZ8/G/Pnzq2aDiIiISK9IHnZiYmLQoUMHWFlZ4d1334Wfnx/c3d0RFRWFTZs2aee7evUqkpKScPToUbRs2RK3b9+u8DoXL16MlStXal8rlUokJCQ813YQERGRfpL8NFZBQQFu3bqFCxcu4LPPPsPly5cxadKkUucNCwsDALRu3RoAkJycDFtbW515Hr9OTk5+4jo1Gg3UarVOIyIiInmSPOz8m5GREczMzErt69ChAwAgKSkJABAaGor27dujUaNG2nl69+6NzMxM7QXOREREZNgkPY21aNEiBAQEIC4uDkqlEiNGjICHhwf69u2Lli1bYsSIETh8+DDS0tLg7OyMVatW4cSJE4iIiAAAHDlyBJGRkdi+fTtmzJgBlUqFhQsXYv369dBoNFJuGhEREekJScOOjY0Ntm3bhsaNGyMzMxNXrlxB3759ERwcjKZNm6JXr16YPHkyzM3NER8fD39/fyxcuFD7/uLiYvTr1w8bNmxAaGgosrOz4efnpzMuDxERERk2BQAhdRFSUyqVyMrKgqWlpcFdv1MsDkhdAlUjI0V/qUugasT927AY4v5d1u9vvbtmh4iIiKgyMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkaxJGnbGjRuHy5cvIzMzE5mZmTh79iy8vLy0/WZmZli3bh1SU1OhVqvx22+/wcbGRmcZzZo1w8GDB5GdnY2UlBQsXboUxsbG1b0pREREpKckDTv37t3DrFmz4OrqipdffhlH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tm2LAwd4jpiIiIj0R7nCTnh4OOzs7BAXF1dqf7169Uo96kNEREQklXKFne+//x7m5uZP7I+Li8OoUaOeuygiIiKiylKusPPHH388tf/hw4fYtm3b89RDREREVKnKfeu5sbExatWqpTNtzJgx2Lp1KyZMmFBphRERERFVhnKHnZ07d+LLL7/Uvv7oo4+wZs0amJubY+7cuVi0aFGlFkhERET0PModdjp16oTAwEDt67Fjx2Ly5MkYMmQIhgwZghEjRlRqgURERETPo8zX7Pz0008AgKZNm2LixInw8fGBQqGAi4sL3njjDbi5ucHExAR2dnbYvHkzgL9PbxERERFJqdzPxrp79y7ef/99nD59Gm+++SZWrVqlHTnZ0tIScXFxqFevXhWUWnX4bCwyFIb47BxDxv3bsBji/l3W7+9y3Y0FAMePH8fGjRuxbds2jBo1Cnv27NH2ubi44MaNGxWrmIiIiKgKlPuanalTp+L8+fMYMWIEjh49qnNB8qBBg7Bjx45KLZCIiIjoeZT7NJYc8TQWGQpDPMxtyLh/GxZD3L/L+v1d7iM7RERERDUJww4RERHJGsMOERERyRrDDhEREckaww4RERHJGsMOERERyRrDDhEREckaww4RERHJGsMOERERyRrDDhEREckaww4RERHJGsMOERERyRrDDhEREckaww4RERHJGsMOERERyZqkYef111/H/v37kZCQACEEBg4cqNO/ZcsWCCF0WkBAgM489evXx44dO5CZmYmMjAz8+OOPMDc3r87NICIiIj0madgxNzfH5cuX8fHHHz9xnoCAAKhUKm0bPny4Tv/OnTvRtm1b9O7dG/369UP37t2xcePGqi6diIiIaggTKVceGBiIwMDAp86Tn5+PlJSUUvucnJzwxhtv4OWXX0Z4eDgA4JNPPsHhw4cxffp0JCUlVXrNREREVLPo/TU7Hh4eSElJQXR0NL777js0aNBA2+fm5oaMjAxt0AGA4OBgFBcXo0uXLk9cpqmpKZRKpU4jIiIiedLrsBMYGIgPPvgAnp6emDlzJtzd3REQEAAjo7/LVqlUuH//vs57ioqKkJ6eDpVK9cTlzp49G1lZWdqWkJBQpdtBRERE0pH0NNaz7NmzR/vvq1ev4sqVK7h9+zY8PDxw9OjRCi938eLFWLlypfa1Uqlk4CEiIpIpvT6y82937tzBgwcP0Lp1awBAcnIybGxsdOYxNjZGgwYNkJyc/MTlaDQaqNVqnUZERETyVKPCTpMmTWBtba298Dg0NBT169dHp06dtPP07NkTRkZGCAsLk6pMIiIi0iOSnsYyNzfXHqUBgBYtWsDFxQXp6elIT0/HvHnz4O/vj+TkZLRq1QpLly7FzZs3ERQUBACIjo5GQEAANm3ahHHjxqFWrVpYt24dfv75Z96JRURERAAkPrLz8ssv49KlS7h06RIAYNWqVbh06RIWLFiAoqIiODs7Y//+/bh+/To2b96M8PBwvP7669BoNNpleHt7Izo6GiEhITh8+DBOnz6Njz76SKItIiIiIn2jACCkLkJqSqUSWVlZsLS0NLjrd4rFAalLoGpkpOgvdQlUjbh/GxZD3L/L+v1do67ZISIiIiovhh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjVJw87rr7+O/fv3IyEhAUIIDBw4sMQ8X375JRITE5GTk4M///wTrVu31umvX78+duzYgczMTGRkZODHH3+Eubl5dW0CERER6TlJw465uTkuX76Mjz/+uNT+GTNmYOLEiRg3bhy6dOmC7OxsBAUFwczMTDvPzp070bZtW/Tu3Rv9+vVD9+7dsXHjxuraBCIiItJzCgBC6iIAQAiBQYMGYd++fdppiYmJWLFiBVasWAEAsLS0REpKCnx9fbFnzx44OTkhKioKL7/8MsLDwwEAffv2xeHDh9G0aVMkJSWVad1KpRJZWVmwtLSEWq2u/I3TY8XigNQlUDUyUvSXugSqRty/DYsh7t9l/f7W22t2WrRogcaNGyM4OFg7LSsrC2FhYXBzcwMAuLm5ISMjQxt0ACA4OBjFxcXo0qXLE5dtamoKpVKp04iIiEie9DbsqFQqAEBKSorO9JSUFG2fSqXC/fv3dfqLioqQnp6unac0s2fPRlZWlrYlJCRUcvVERESkL/Q27FSlxYsXw9LSUtuaNGkidUlERERURfQ27CQnJwMAbG1tdabb2tpq+5KTk2FjY6PTb2xsjAYNGmjnKY1Go4FardZpREREJE96G3bu3LmDpKQkeHp6aqcplUp06dIFoaGhAIDQ0FDUr18fnTp10s7Ts2dPGBkZISwsrNprJiIiIv1jIuXKzc3NdcbNadGiBVxcXJCeno74+HisXr0aX3zxBW7cuIE7d+7gq6++QmJiIv744w8AQHR0NAICArBp0yaMGzcOtWrVwrp16/Dzzz+X+U4sIiIikjdJw87LL7+M48ePa1+vWrUKALB161aMGjUKS5cuhbm5OTZu3Ih69erh9OnT8PLyQn5+vvY93t7eWLduHUJCQlBcXAx/f39MnDixujeFiIiI9JTejLMjJY6zQ4bCEMfhMGTcvw2LIe7fZf3+lvTIDhHpt7p166Jhw4ZQKBRSl2LQhBBITU1FTk6O1KUQ1UgMO0RUgkKhwKhRo+Dh4SF1KfQPx48fx5YtWyCEwR+QJyoXhh0iKmHUqFFwd3fHnj17EB0djcLCQqlLMmgmJiZwcnLC0KFDAQA//fSTxBUR1SwMO0Skw9zcHB4eHtizZw8OHTokdTn0f27dugUAGDZsGH7++Wee0iIqB70dZ4eIpGFtbQ3g76EdSL88/pk0bNhQ4kqIahaGHSLS8fhiZJ660j+Pfya8YJyofBh2iIiISNYYdoiIiEjWGHaIqEZycHCAEAIuLi4AAHd3dwghYGVlBQDw8fFBRkbGM5cjhMDAgQOrtFYikhbDDhFJ6tixY9pHxfzTP8PKli1bsHfvXp3++Ph4qFQqXL16tdTl7tmzB46OjtrX8+bNw8WLF0vMp1KpEBAQ8DybQER6jreeE1GNVFxcjJSUlCf25+XlIS8v75nLedoyiEgeeGSHiPTavHnz4Ovri0GDBkEIASEE3N3dS5zG+rd/Hhny8fHB/Pnz0aFDB+0yfHx8AJQ8jdW0aVPs2bMHGRkZSEtLwx9//AEHBwdtv7u7O8LCwvDo0SNkZGTg9OnTsLe3r8JPgIieF4/sEJFeW758OV566SVYWlpi1KhRAID09HTY2dmVeRl79uxBu3bt4OXlhV69egEAMjMzS8xnYmKCoKAghIaG4vXXX0dhYSG++OILBAYGwtnZGcXFxfjjjz+wadMmDB8+HKampnjllVf4+AYiPcewQ0R6LTs7G7m5uTAzM6vwKae8vDw8evQIhYWFT13GsGHDYGRkhP/85z/aaaNGjcLDhw/h4eGB8+fPo169ejh48CBu374NgIMvEtUEPI1FRPR/XFxc0Lp1a6jVam1LT09H7dq10apVK2RkZGDLli0ICgrC/v37MXHiRKhUKqnLJqJnYNghIkllZWVpbxf/p3r16pV6qqkqWVhYIDw8HB06dNBpjo6O2LVrFwBg9OjRcHNzw9mzZzFs2DBcv34dXbp0qdY6iah8eBqLiCQVExODPn36lJjeqVMnXL9+HQCg0WhgbGz8XOspyzIuXLiAYcOG4f79+1Cr1U+c79KlS7h06RK++eYbnD17FiNGjEBYWNhz1UdEVYdHdohIUhs2bICjoyPWrFmD9u3bw9HREVOmTMHw4cOxYsUKAMDdu3fh7OwMR0dHWFtbw8Sk/H+n3b17Fy1atICLiwusra1hampaYp6dO3ciNTUV+/btw2uvvYbmzZvD3d0da9asQZMmTdC8eXMsWrQIXbt2hb29PXr37o0XXngBUVFRz/05EFHVYdghIknduXMH3bt3h5OTE4KDgxEWFoahQ4diyJAhCAoKAgBs2rQJMTExOH/+PFJTU9GtW7dyr8ff3x+BgYE4duwYUlNTMXz48BLz5Obmonv37oiLi8Pvv/+OqKgobN68GbVr10ZWVhZycnLg5OQEf39/XL9+HRs3bsT69evxww8/PPfnQERVh6exiEhy58+fR9++fZ/Yn5qaWmr/P5/+feLECZ3Xfn5+8PPz077WaDQYMmTIU5cB/D3IoK+vb6l1qNVqvPPOO0+sk4j0E4/sEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrPHWcwO36mpDqUsgIiKqUjyyQ0RERLLGsENEVAYODg4QQsDFxQUA4O7uDiFEqQ8xJSL9wtNYRFRmKyJCq3V909q7Vev6yuPs2bNQqVTV/mR2Iio/vT6yM2/ePAghdNo/H7hnZmaGdevWITU1FWq1Gr/99htsbGwkrJiIDEVBQQFSUlKkLoOIykCvww4AXL16FSqVSttee+01bd+qVavQv39/DBkyBO7u7rCzs8Pvv/8uYbVEJCWFQoFPP/0UN27cQF5eHmJjY/HZZ58BANq1a4eQkBDk5OQgNTUVP/zwA8zNzXXeO2fOHMTHxyMvLw8XL1586vO6/n0ay8fHBxkZGejTpw8iIyOhVqsREBAAlUqlfY+xsTHWrFmDjIwMpKam4ptvvsHWrVuxd+/eKvpEiAioAWGnsLAQKSkp2paWlgYAsLS0xJgxYzB16lQcO3YMFy5cwKhRo9CtWzd06dJF4qqJSAqLFy/GrFmz8NVXX6FNmzYYMWIEUlJSULduXQQFBSEjIwOdO3fGkCFD0KtXL6xbt0773kmTJmHatGmYPn06nJ2dERQUhP3796N169ZlXn/dunUxffp0jBw5Et27d4e9vT2WL1+u7Z85cya8vb21v6ssLS0xaNCgyvwIiKgUeh92XnjhBSQkJODWrVvYsWMHmjVrBgBwdXWFqakpgoODtfPGxMQgNjYWbm5PP89vamoKpVKp04ioZrOwsMCkSZMwY8YMbNu2Dbdv38aZM2ewefNmjBgxArVr18YHH3yAa9eu4dixY5gwYQJGjhypPfU9ffp0LFmyBHv27MH169cxa9YsXLp0CZMnTy5zDaamphg3bhzCw8Nx8eJFrFu3Dp6entr+Tz75BIsXL8Yff/yBmJgYTJgwAQ8fPqzkT4KI/k2vw05YWBh8fX3h5eWF//73v2jRogVOnToFCwsLqFQq5Ofnl7g4MCUlReewcWlmz56NrKwsbUtISKjKzSCiavDSSy+hdu3aCAkJKbXv8uXLyMnJ0U47c+YMjI2N8eKLL0KpVKJJkyY4c+aMzvvOnDmDl156qcw1ZGdn4/bt29rXSUlJ2jBlaWkJlUqFc+fOafuLi4sRHh5e5uUTUcXo9d1YgYGB2n9HREQgLCwMsbGxGDp0KHJzcyu83MWLF2PlypXa10qlkoGHqIZ7nt8JlaWgoEDntRACRkZ6/TclkUHQ67Dzb5mZmbh+/Tpat26NP//8E2ZmZrCystI5umNra4vk5OSnLkej0UCj0VR1uURUjW7cuIGcnBx4enpi8+bNOn1RUVHw9fVF3bp1tUd3unXrhqKiIsTExECtViMhIQHdunXDyZMnte/r1q2bzpGY55GVlYXk5GR07twZp06dAgAYGRmhU6dOuHTpUqWs4984QjrR32rUnxzm5uZo1aoVkpKSEB4eDo1Go3M+3NHREQ4ODggNrd6xQIhIevn5+ViyZAmWLl2KkSNHomXLlujSpQtGjx6NnTt3Ii8vD35+fmjbti08PDywdu1abN++Hffv3wcALFu2DDNnzsTQoUPh6OiIxYsXo0OHDlizZk2l1bh27VrMnj0bAwYMgKOjI9asWYP69etDCFFp6yCikvT6yM6yZctw4MABxMbGws7ODl9++SWKioqwe/duZGVlYfPmzVi5ciXS09ORlZWFtWvX4uzZswgLC5O6dCKSwFdffYXCwkIsWLAAdnZ2SEpKwvfff4/c3Fz07dsXa9aswV9//YWcnBz4+/tj6tSp2vd+++23sLKywooVK2BjY4PIyEgMGDAAN2/erLT6lixZApVKhW3btqGoqAgbN25EUFAQioqKKm0dRFSSXoedpk2bYvfu3bC2tsaDBw9w+vRpdO3aFampqQCAKVOmoLi4GP7+/jAzM0NQUBDGjx8vcdVE8qXPIxoDf18js2jRIixatKhE39WrV3WOBJf23gULFmDBggWl9sfGxkKhUGhfnzhxQue1n58f/Pz8dN6zb98+nXmKioowceJETJw4EcDfY/tERUXhl19+KdsGElGF6HXYGT58+FP78/PzMWHCBEyYMKGaKiIiqjh7e3v06dMHJ06cgJmZGSZMmIAWLVpg165dUpdGJGs16podIqKarLi4GL6+vvjrr79w5swZtG/fHr169UJ0dLTUpRHJml4f2SEikpN79+7pPPKGiKoHj+wQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQkWwcO3YMq1atqvb1+vj4ICMjo9rXS0Rlw3F2iKjMisWBal2fkaJ/ta6vLO7cuYPVq1frPCB0z549OHz4sIRVEdHTMOwQET2nvLw85OXlSV0GET0BT2MRkawYGRlhyZIlSEtLQ1JSEubNm6fts7KywqZNm3D//n1kZmYiJCQEzs7O2v6WLVvijz/+QHJyMtRqNc6dO6fz8NBjx46hefPmWL16NYQQEEIAKHkaa968ebh48SLef/993LlzBw8fPsTu3bthYWGhncfCwgI7duzAo0ePkJiYiMmTJ0t2Go5I7hh2iEhWfHx8kJ2djS5dumDGjBmYO3cuevXqBQD49ddfYWNjgzfeeAOurq64cOECQkJCUL9+fQB/B5DDhw/D09MTHTt2RGBgIA4cOIBmzZoBAN555x3Ex8djzpw5UKlUUKlUT6yjVatWGDRoEPr164d+/frB3d0ds2bN0vavXLkS3bp1w4ABA9C7d2+8/vrr6NSpUxV+MkSGi6exiEhWrly5ggULFgAAbt68iQkTJsDT0xO5ubl45ZVXYGNjA41GAwD49NNPMWjQILz77rvYtGkTrly5gitXrmiXNXfuXLz99tsYMGAA1q9fj4yMDBQVFUGtViMlJeWpdRgZGcHX1xePHj0CAGzfvh2enp744osvYGFhAR8fH4wYMQJHjx4FAIwaNQqJiYlV8ZEQGTyGHSKSlX+GFQBISkqCjY0NXFxcYGFhgbS0NJ3+OnXqoFWrVgAAc3NzzJ8/H2+99RYaN24MExMT1KlTB/b29uWu4+7du9qg8886gL9Pl5mamuLcuXPa/qysLMTExJR7PUT0bAw7RCQrBQUFOq+FEDAyMoKFhQWSkpLg4eFR4j0PHz4EACxfvhy9e/fG9OnTcfPmTeTm5uK3336DqalppdVBRNWPYYeIDMKFCxegUqlQWFiI2NjYUufp1q0btm7dij/++APA30d6mjdvrjOPRqOBsbHxc9Vy+/ZtaDQadO7cGfHx8QAAS0tLODo64uTJk8+1bCIqiX9mEJFBCA4ORmhoKP744w/07t0bDg4OcHNzw8KFC+Hq6goAuHHjBt555x24uLjA2dkZu3btKnE05u7du+jevTvs7OxgbW1doVoePXoEPz8/LFu2DB4eHmjTpg02b96M4uJi7R1eRFR5GHaIyGC8+eabOHnyJLZs2YLr16/j559/hoODg/Zi46lTpyIjIwNnz57FgQMHEBQUhAsXLugsY+7cuWjevDlu3bqF1NTUCtcydepUhIaG4uDBgwgODsaZM2cQFRXF8XqIqoACgMH/GaFUKpGVlQVLS0uo1Wqpy6lWKyJCpS6BqtG09m7PnMfBwQFfffUV5syZ88TTPVT56tati4SEBEybNg0//fRTqfOU92fD/duwlGX/lpuyfn/zmh0iIgl06NABTk5OOHfuHKysrDB37lwAwL59+ySujEh+GHaIiCQyffp0vPjii9BoNAgPD8frr79e4tZ4Inp+DDtERBK4dOkSXn75ZanLIDIIvECZiIiIZI1hh4h0PL712cSEB371zeOfCW9PJyofhh0i0vH4mhEnJyeJK6F/e/wzeZ5b3okMEf90IyId2dnZOH78OIYOHQoAiI6ORmFhocRVGTYTExM4OTlh6NChOH78OHJycqQuiahGYdghohK2bNkCABg2bJjEldA/HT9+XPuzIaKyY9ghohKEEPjpp5/w888/o2HDhlAoFFKXZNCEEEhNTeURHaIKYtghoifKyclBXFyc1GUQET0X2VygPH78eNy5cwe5ubn43//+h86dO0tdEhEREekBWYSdoUOHYuXKlfjyyy/RqVMnXL58GUFBQWjUqJHUpREREZHEZBF2pk6dik2bNmHr1q2IiorCuHHjkJOTg9GjR0tdGhEREUmsxl+zU6tWLbi6umLx4sXaaUIIBAcHw82t9CfAmpqawszMTPtaqVTq/NeQmBoZS10CVSND/H/ckHH/NiyGuH+XdZtrfNhp2LAhTExMkJKSojM9JSXliYOizZ49G/Pnzy8xPSEhoSpKJNIbE7KypC6BiKqIIe/fSqUSarX6if01PuxUxOLFi7Fy5UqdaQ0aNEB6erpEFVF1UiqVSEhIQJMmTZ66cxBRzcP92/AolUokJiY+dZ4aH3ZSU1NRWFgIW1tbnem2trZITk4u9T0ajQYajUZnGncKw6NWq/lzJ5Ip7t+Goyw/5xp/gXJBQQHCw8Ph6empnaZQKODp6YnQ0FAJKyMiIiJ9UOOP7ADAypUr4efnh/Pnz+PcuXOYPHkyzM3NOaw6ERERySPs/PLLL2jUqBEWLFgAlUqFS5cuwcvLC/fv35e6NNJD+fn5mD9/PvLz86UuhYgqGfdvKo0CgJC6CCIiIqKqUuOv2SEiIiJ6GoYdIiIikjWGHSIiIpI1hh0iIiKSNYYdIiIikjWGHSIiIpI1WYyzQ0REhsnIyAi+vr7w9PSEjY0NjIx0/4b/5+j6ZLgYdoiIqMZas2YNfH19cejQIVy9ehVCcOg4KomDCpJBsLGxwfLly7V//SkUCp1+ExPmfqKa6MGDB/jggw8QEBAgdSmkx/gbngzC1q1bYW9vj6+++gpJSUn8649IJjQaDW7evCl1GaTneGSHDEJWVhZef/11XL58WepSiKgSTZ06FS1btsSECROkLoX0GI/skEGIj48vceqKiGomf39/ndc9e/bEG2+8gWvXrqGgoECnb/DgwdVZGukphh0yCJMnT8Y333yDsWPHIjY2VupyiOg5ZGZm6rzeu3evRJVQTcHTWGQQ0tPTUbduXZiYmCAnJ6fEX3/W1tYSVUZERFWNR3bIIEyePFnqEoioCtSuXRsKhQK5ubkAAHt7e7z99tuIjIzEn3/+KXF1pE8EGxsbGxtbTWxBQUFi7NixAoCwsrISycnJIi4uTuTk5Ihx48ZJXh+bfjQ+LoIMhpGREd555x18/vnn+PzzzzFo0KASo60SUc3SqVMnnDp1CgDw7rvvIjk5GQ4ODvjggw8wceJEiasjfcHTWGQQWrVqhcOHD6NJkyaIiYkBAMyePRvx8fF46623cPv2bYkrJKKKqFu3LtRqNQCgT58++P333yGEwP/+9z84ODhIXB3pC/5ZSwbh22+/xa1bt9CsWTO4urrC1dUV9vb2uHPnDr799lupyyOiCrp58yYGDRqEpk2bom/fvjhy5AiAv0dNz8rKkrg60ieSn0tjY6vq9ujRI9GuXbsS052dnYVarZa8PjY2toq1wYMHi/z8fFFYWCiCgoK002fNmiUOHz4seX1s+tF4GosMQn5+PpRKZYnpFhYW0Gg0ElRERJXB398f9vb2aNy4sc4I6SEhIRx/h3RInrjY2Kq6+fn5iYiICPHKK69op3Xp0kVcuXJFbNmyRfL62NjY2NiqrnFQQTIIVlZW8PPzQ//+/bUDCpqYmGD//v3w9fXluX2iGszV1RVDhw6Fvb09TE1Ndfr4uAgCeDcWGYjMzEwMGjQIrVu3hpOTEwAgKioKt27dkrgyInoew4YNw7Zt2xAUFIQ+ffrgyJEjcHR0hK2tLU9jkRaP7BARUY11+fJl/PDDD/juu++QlZUFFxcX3LlzBz/88AOSkpIwf/58qUskPcCwQ7K1YsUKzJkzBzk5OVixYsVT5502bVo1VUVElenRo0do27YtYmNjkZqaCg8PD1y9ehVOTk44evQo7OzspC6R9ABPY5FsdezYEbVq1dL+m4jkJyMjQ3unZUJCAtq1a4erV6+iXr16qFu3rsTVkb5g2CHZ6tmzZ6n/JiL5OHnyJHr37o2rV6/i119/xZo1a9CzZ0/07t0bISEhUpdHekTyW8LY2Kq6bd68WVhYWJSYXrduXbF582bJ62NjY6tYq1+/vmjcuLEAIBQKhZg5c6bYt2+fWL58uahXr57k9bHpR+M1O2QQCgsL0bhxYzx48EBnurW1NZKTk7Wnu4iISH54GotkTalUQqFQQKFQQKlUIi8vT9tnbGyMN998E/fv35ewQiIqr9JGQ3+Sxw8JJcPGsEOy9vDhQwghIITA9evXS/QLITBv3jwJKiOiinq8Xz+NQqGAEAImJvyaI4YdkrkePXpAoVDg6NGjGDx4MNLT07V9Go0GsbGxSEpKkrBCIiqvHj16SF0C1TC8ZocMgr29PeLj45/51yAREckPww4ZlDp16pT6/JyIiAiJKiKiivDz88PHH3+MR48eAQCcnZ0RGRmJwsJCiSsjfcSwQwahYcOG2LJlC954441S+3len6hm+fcdlpmZmejQoQPu3LkjcWWkj4ykLoCoOqxevRr16tVDly5dkJubCy8vL/j4+ODGjRsYMGCA1OURUTkpFIqnvib6J/45SwahZ8+eGDhwIMLDw1FcXIzY2FgEBwcjKysLs2fPxuHDh6UukYiIqgjDDhkEc3Nz7Xg6GRkZaNSoEW7cuIGIiAh06tRJ4uqIqCLatGmjvcNSoVDAyckJFhYWOvPwejwCGHbIQMTExODFF19EbGwsLl++jLFjx+Lu3bsYN24cbz0nqqFCQkJ0Tl8dPHgQwN/jZ3GcHfon/l9ABmHNmjVo3LgxAODLL79EYGAgvL29odFo4OvrK21xRFRuLVq0kLoEqkF4NxYZpDp16sDJyQlxcXFIS0uTuhwiIqpCDDtEREQkazyNRbK1YsWKMs87bdq0KqyEiIikxLBDstWxY8cyzcdHSBARyRtPYxEREZGs8cgOERHVeA0bNsSLL74I4O+hJlJTUyWuiPQJww7Jlr+/f5nnHTx4cBVWQkRVpW7duli7di1GjhwJY2NjAEBRURG2bduGTz75BLm5uRJXSPqAz8Yi2crMzCxzI6KaaeXKlXB3d8eAAQNQr1491KtXDwMHDoS7u3u5blIgeeM1O0REVGM9ePAA7777Lk6cOKEz3cPDA7/88gtsbGwkqoz0CY/sEBFRjVW3bl2kpKSUmH7//n3UrVtXgopIH/HIDslWeHg4PD098fDhQ1y4cOGpt5i7urpWY2VEVFmCg4ORlpaGDz74APn5+QCA2rVrw8/PDw0aNEDv3r0lrpD0AS9QJtnat2+f9pffvn37OJ4OkQxNmjQJQUFBuHfvHi5fvgwAcHFxQV5eHvr27StxdaQveGSHiIhqtDp16sDb2xtOTk4AgKioKOzcuRN5eXkSV0b6gmGHDMKtW7fQuXNnpKen60y3srLChQsX0KpVK4kqIyKiqsbTWGQQmjdvrh2D45/MzMzQtGlTCSoiosoQGxuL48eP48SJEzh27Bju3LkjdUmkhxh2SNb69++v/Xffvn11xtQxNjaGp6cnfzkS1WCfffYZunfvjpkzZ2LTpk1ISEjAiRMncOLECRw/fhw3b96UukTSAzyNRbJWVFQE4O+HfSoUCp2+goIC3L17F9OmTcOhQ4ekKI+IKpFKpYK7uzv69euHYcOGwcjICCYm/JueeGSHZO7xqavbt2+jc+fOSEtLk7giIqpsderUwWuvvQYPDw/06NEDHTt2xNWrV3H8+HGpSyM9wSM7ZLCsrKz4qAiiGu7MmTPo2LEjoqKitNfunDx5Eg8fPpS6NNIjHEGZDMKMGTMwdOhQ7etffvkF6enpuHfvHpydnSWsjIieh5OTE7KzsxEdHY3o6GhERUUx6FAJDDtkEMaNG4f4+HgAQK9evdCrVy94eXkhICAAy5Ytk7g6Iqooa2tr9OzZE//73//Qt29fnDlzBvfu3cPOnTvxn//8R+rySI8INja5t5ycHNG0aVMBQKxevVp8//33AoB44YUXRHp6uuT1sbGxVU5zdXUVW7ZsERqNRhQWFkpeD5t+NB7ZIYOQkZGBZs2aAQC8vLwQHBwMAFAoFKWOv0NE+m3OnDmoU6cOOnbsiClTpmDfvn1IS0tDaGgonJ2dsXbtWrzzzjtSl0l6RPLExcZW1W3t2rXizp074siRI+LBgwfC3NxcABDDhg0T4eHhktfHxsZWvlZYWCgaNWokCgoKxLlz58SyZctEv379hKWlpeS1self463nZBCmTJmCu3fvolmzZpgxYways7MBAI0bN8Z3330ncXVEVF6Px81q0KAB1Gq1xNWQvuOt50REVOMUFRXB1tYWqampUpdCNQDDDslW//79ERAQgMLCQp3HRpTmwIED1VQVEVWGoqIiZGZmQoinf4VZW1tXU0Wkzxh2SLaKioqgUqnw4MED7WMjSiOE4JDyRDVMUVERJk+e/MyBQbdt21ZNFZE+Y9ghIqIa559/zBA9C/+cJdlTKBTw9fXFO++8g+bNm0MIgdu3b8Pf3x/bt2+XujwiqoBnnb4i+ieOs0Oyt3//fvz4449o0qQJIiIicO3aNTRv3hxbt27F3r17pS6PiCrg8d1YRGUl+f3vbGxV1Xx9fUVmZqbw8PAo0dejRw+RmZkpRo4cKXmdbGxsbGxV13jNDslaUFAQjh49iiVLlpTaP3v2bLi7u8PLy6uaKyMiourC01gka87OzggMDHxif0BAAFxcXKqxIiIiqm4MOyRrDRo0QEpKyhP7U1JSUL9+/WqsiIiIqhvDDsmasbExCgsLn9hfVFTEMXaIiGSOv+VJ1hQKBbZu3Yr8/PxS+83MzKq5IiIiqm4MOyRrfn5+z5yHI6wSEckb78YiIiIiWeM1O0RERCRrDDtEREQkaww7REREJGsMO0RERCRrDDtEREQkaww7REREJGsMO0RERCRr/w9M0Wpv/x2y+gAAAABJRU5ErkJggg==", - "text/plain": [ - "
" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's compare the total costs on a production basis. This will account for the greater efficiency provided by the distillation column relative to the less-expensive second flash unit:" ] - }, - "metadata": { - "filenames": { - "image/png": "C:\\Users\\dkgun\\src\\dangunter\\examples\\idaes_examples\\notebooks\\_build\\jupyter_execute\\docs\\flowsheets\\hda_flowsheet_with_costing_doc_24_2.png" - } - }, - "output_type": "display_data" - } - ], - "source": [ - "# Compare operating costs (per year)\n", - "\n", - "two_flash_opcost = {\n", - " \"cooling\": value(3600 * 24 * 365 * m.fs.cooling_cost / 1e3),\n", - " \"heating\": value(3600 * 24 * 365 * m.fs.heating_cost / 1e3),\n", - "}\n", - "distillation_opcost = {\n", - " \"cooling\": value(3600 * 24 * 365 * n.fs.cooling_cost / 1e3),\n", - " \"heating\": value(3600 * 24 * 365 * n.fs.heating_cost / 1e3),\n", - "}\n", - "\n", - "two_flash_opdf = pd.DataFrame(\n", - " list(two_flash_opcost.items()), columns=[\"Utilities\", \"Two Flash\"]\n", - ").set_index(\"Utilities\")\n", - "distillation_opdf = pd.DataFrame(\n", - " list(distillation_opcost.items()), columns=[\"Utilities\", \"Distillation\"]\n", - ").set_index(\"Utilities\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "opcosts = two_flash_opdf.add(distillation_opdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(opcosts) # view dataframe before plotting\n", - "\n", - "opplot = opcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Operating Costs\", ylabel=\"$1000/year\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Costs in $1000:\n" - ] }, { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Costscapitaloperating
Distillation45.553829427.596731
Two Flash39.601876419.122339
\n", - "
" + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Two flash case over one year: $459K / 4477 kmol benzene = $102.45 per kmol benzene produced\n", + "Distillation case over one year: $473K / 5108 kmol benzene = $92.63 per kmol benzene produced\n" + ] + } ], - "text/plain": [ - "Costs capital operating\n", - "Distillation 45.553829 427.596731\n", - "Two Flash 39.601876 419.122339" + "source": [ + "two_flash_cost = value(1e3 * sum(two_flash_totcost[idx] for idx in two_flash_totcost))\n", + "two_flash_prod = value(\n", + " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] * 365 * 24 * 3600\n", + ")\n", + "distillation_cost = value(\n", + " 1e3 * sum(distillation_totcost[idx] for idx in distillation_totcost)\n", + ")\n", + "distillation_prod = value(n.fs.D101.condenser.distillate.flow_mol[0] * 365 * 24 * 3600)\n", + "\n", + "print(\n", + " f\"Two flash case over one year: ${two_flash_cost/1e3:0.0f}K / {two_flash_prod/1e3:0.0f} kmol benzene = ${two_flash_cost/(two_flash_prod/1e3):0.2f} per kmol benzene produced\"\n", + ")\n", + "print(\n", + " f\"Distillation case over one year: ${distillation_cost/1e3:0.0f}K / {distillation_prod/1e3:0.0f} kmol benzene = ${distillation_cost/(distillation_prod/1e3):0.2f} per kmol benzene produced\"\n", + ")" ] - }, - "metadata": {}, - "output_type": "display_data" }, { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHvCAYAAACykR7/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAABItklEQVR4nO3deXhN5/7H/U8GCYkkNIaYotTPPKdqahszVWMdtFUEp6paFKeGao1tVc1ztVVTPS0tqsaYKVIOSkMSYyTGICKJkNF6/vDYj32CymQnK+/Xdd1Xs+977bW/a8duPnsN97KTZAgAAMCk7G1dAAAAQFYi7AAAAFMj7AAAAFMj7AAAAFMj7AAAAFMj7AAAAFMj7AAAAFMj7AAAAFMj7AAAAFMj7ADIUmPGjJFhZN5E7Zm9vtzo448/VnBwsOzs7GxdiiSpUqVKSkpKUpUqVWxdCkyKsAOkUc+ePWUYhnx8fB45vnPnTgUGBlr1hYaGyjAMGYahlJQURUVF6e+//9aCBQv00ksvPfH1XnvtNRmGoUuXLj3VHydfX1/La/1T+yfFihXTmDFjVKNGjX9cNqMWLVpkVVt0dLSOHj2qIUOGyMnJKctf/2GVKlXSmDFjVLp06TQ9r0aNGlq2bJnCw8MVHx+vyMhIbd26VX5+frK3z/z/3abn9+Pm5qbhw4dr0qRJMgwj1fv+uLZo0SJJ9/99P9wfGRmpgwcPqlevXo/89+nr66tVq1bpypUrSkhIUEREhH7//Xd17NjRskxwcLA2bNig8ePHZ/xNAR7B0dYFALnFX3/9palTp0q6/wenUqVK6ty5s/r27atp06Zp6NChj3xet27dFBoaqjJlyqhJkybavn37E18nODhY77zzjlXfxIkTdfv2bX3xxRdpqrl48eIaO3aszp8/r2PHjqXpuekRHx+vf//735KkAgUKqFOnTpo6darq1Kmjt956K8tf/4HKlStr7Nix2rVrl8LCwp7qOX369NE333yjiIgILVu2TKdPn5abm5uaNm2qhQsXqlixYpo4cWKm1pme30/v3r3l6Oion376SZK0YMECbdu2zTJepkwZTZgwQQsWLNAff/xh6T979qzl5wsXLmjkyJGSpMKFC6tHjx764YcfVL58eUu/JI0dO1ZjxozRqVOntGDBAoWFhcnT01OtW7fW6tWr9fbbb1vq+Oabb7Rp0yaVLVtW586dS/+bAjyGQaPRnr717NnTMAzD8PHxeeT4zp07jcDAQKu+0NBQY926damWzZs3r7F69WrDMAyjX79+qcZdXFyM2NhY48MPPzQOHz5s/PDDD+mqOTAw0Ni5c2ean+fj42MYhmH07Nkz3e/XmDFjDOP+bqQntkWLFhmxsbFWfXZ2dsbBgwcNwzCMYsWKpWl9GWmdOnUyDMMwfH19n2r5unXrGklJScaePXuM/PnzP/J9zMh7mJm/n6NHjxpLly5N9zof9e87X758Rnh4uBEbG2s4OjpavYcrV6609D3cWrRoYbz++uuWx46OjkZkZKQxbty4LP3d0nJn4zAWYEPx8fHq3r27IiMjNWrUqFTjHTt2VL58+fTLL7/o559/1htvvCFnZ+dMee0yZcpo5cqVioyMVFxcnAICAtS6dWvLuK+vrw4dOiRJWrx4seWwRc+ePSVJL7/8slauXKmwsDDFx8crPDxc06ZNU968eTOlPkkyDEO7du2SJD3//POPXc7Pz0/bt29XRESE4uPjdeLECfXr1y/VcqGhoVq3bp0aNmyoAwcO6O7duzp79qy6d+9uWaZnz5769ddfJUm7du2ybLevr+9jX//BeUTdunXT7du3U40fPnxYS5YssTx2cXHRlClTLIe7QkJCHrlnr1mzZvrjjz8UFRWl2NhYhYSEWPbO/dPv51Gef/551ahRw2pPTma4e/eu/vzzT+XPn1+FCxeWJE2YMEGRkZHq3bu3kpOTUz1ny5Yt2rBhg+VxcnKydu3apfbt22dqbYDEOTtAunl4eMjT0zNVy5MnT5rWExcXpzVr1qhkyZKqXLmy1Vi3bt20c+dORURE6Oeff5abm5vatm2b4dqLFCmi/fv3q2XLlpo3b55GjRqlvHnz6vfff1eHDh0k3T8c9tlnn0m6f6jjnXfe0TvvvKM9e/ZIkjp37iwXFxfNnz9fAwYMkL+/vwYMGKClS5dmuL6HvfDCC5KkyMjIxy7z/vvvKywsTF9++aWGDh2qCxcuaP78+erfv3+qZcuVK6dff/1VW7du1dChQxUVFaXFixdb3vs9e/Zo5syZkqQvvvjCst3BwcGPfO18+fKpadOm2rNnjy5cuPBU2/T7779r8ODB2rx5s4YMGaKTJ09qypQpmjZtmmWZypUra/369XJ2dtbo0aM1dOhQ/f7772rYsKGkf/79PEqDBg0kSUeOHHmqOtOibNmySk5O1q1bt1SuXDlVqlRJv/322yPD3+McPnxYVatWlZubW6bXB9h89xKNlpPag8NYT/K0h7EetEGDBhmGYRht27a19BUuXNhITEw0+vTpY+nbu3evsWbNmjTX/L+HsaZNm2YYhmE0bNjQ0ufq6mqcPXvWOHfunGFnZ2dITz6kkTdv3lR9w4cPN1JSUoxSpUpZ+tJ6GMvT09Pw9PQ0ypYta4wYMcJISUkxjh49+sT1PaqWTZs2GWfOnEn1ezAMw3j55ZctfYUKFTLu3r1rTJ482dKXlsNY1apVMwzDMKZPn/5Uv4t27doZhmEYn3zyiVX/ypUrjZSUFKNs2bJW/yY8PT0fu660HsYaP368YRiG4erqmu517ty50wgKCrL8nipUqGDMmDHDMAzDWLt2rSHJaNu2rWEYhjFo0KA0/Tt98803DcMwjDp16qT53ziN9qTGCcpAOvXv31+nTp1K1T916lQ5ODikaV0Pvv0+/I32zTff1L1797Rq1SpL308//aSpU6eqQIECunXrVvoKl9S6dWsdOHBA+/bts/TFxcXp22+/1VdffaXKlSvrxIkTT1xHfHy85WcXFxfly5dP+/fvl729vWrVqvXUezkelj9/ft24ccOqb9++fVaHmf6pFnd3d+XJk0e7d+9Wq1at5O7urpiYGMv4iRMntHfvXsvjGzdu6OTJkypbtmya633wepIUGxv7VMu3bt1aycnJmjVrllX/1KlT1blzZ7322muaO3eu5ffbvn17yxVTGeXp6amkpCTFxcVlaD2VKlWy+j3du3dP69evV+/evSWl/T15ICoqSpJUqFChDNUH/C/CDpBOBw8e1OHDh1P1R0VFpfl/1vnz55dk/cfhnXfe0cGDBy2Hx6T7V3Q5Ozurc+fO+u6779Jde+nSpXXgwIFU/Q8O1ZQuXfofw06pUqU0fvx4tWvXTs8995zVmIeHR7rqunv3ruUwXUJCgkJDQ3Xp0qV/fF6DBg00btw41a9fX66urqlqeTjshIeHp3p+VFSUChYsmK6aH6z7aQ+9lC5dWpcvX051eOfh916SVqxYoX//+99auHChvvrqK23fvl2rV6/Wr7/+avN5hkJDQ/Xuu+/KMAzFx8fr9OnTun79umU8re/JAw8uXbf19sF8CDtANlC1alVJ0pkzZyTdP6/kwfw7D/oe1q1btwyFnYyyt7fX1q1b9dxzz2nSpEkKCQlRXFycSpQooSVLlqR7TpmUlJR/vLT+f5UtW1bbt29XSEiIhgwZogsXLigxMVGtW7fWkCFDUtWSkpLyyPWkd4K9M2fOKCkpSdWqVUvX8x8nPj5er776qho3bqzXX39drVq10ptvvqnt27erRYsWunfvXprXGRkZqTx58ih//vxpOpfmf8XFxT3x9xQSEiJJaX5PHgTO/927B2QUYQewMVdXV3Xs2FHh4eGWb/fdunVTYmKiunfvnuqP88svv6yBAweqVKlS6TpUJElhYWGqUKFCqv6KFStaxqXHf8OuVq2aKlSooB49emjZsmWW/mbNmqWrnoxo27at8ubNq3bt2lm9H40bN073OtOyZ+Hu3bvasWOHmjRpopIlS+rixYtPXD4sLEzNmjVLFTj+971/UMeOHTu0Y8cODR06VCNHjtSXX36pxo0ba/v27WneA/IghJQpUybVxJeZ6fTp0woJCVH79u01aNCgpz5sVqZMGaWkpDzy8DCQEVyNBdhQ3rx5tWzZMnl6elpN+NetWzf98ccfWrlypVatWmXVJk+eLEkZmmRv48aNqlu3rurVq2fpc3FxUd++fRUaGqqgoCBJsvyRKlCggNXzHwSw/90bMmjQoHTXlF6PqsXd3V29evVK9zoft92PM27cONnZ2WnZsmWpDqNJUu3atdWjRw9J9997R0dHffjhh1bLDB48WPfu3dOmTZsk6ZGH1Y4ePSpJlukH0lpnQECAJOnFF198quUzYsyYMSpUqJC+//77R57D1rx5c73++utWfT4+Pjpx4oTVYUcgM7BnB3hGSpQooW7dukm6f45O5cqV1blzZxUrVkxTpkzRt99+K0l66aWX9H//93+aM2fOI9dz+fJlHTlyRN26ddPXX3+drlq++uorvfXWW9q0aZNmzZqlmzdvqmfPnipTpow6depk2WNw9uxZRUVFqV+/foqNjVVcXJwOHDigkJAQnTlzRlOmTFGJEiUUExOjTp06pfu8l4zYsmWLEhIStG7dOi1YsED58+fXu+++q2vXrql48eLpWufRo0eVnJys4cOHy8PDQwkJCdqxY4fVeSkPCwgI0AcffKB58+YpJCTEagblRo0aqV27dvr0008lSevWrdOOHTv0xRdf6Pnnn9exY8fUokULdejQQdOnT7fMHjx69Gi9+uqr2rBhg8LCwlSkSBH1799fFy5csJxg/bjfz/nz5x9ZZ2hoqAIDA9WsWTPL7R+yysqVK1WtWjV9+umnqlWrln766SfLDMqtWrVSs2bNrAK7o6OjfH19NW/evCytC7mXzS8Jo9FyUkvvDMoPpKSkGLdu3TICAwONBQsWpLrMdubMmYZhGEaZMmUeW8Po0aMNwzCMatWqPVXNj5pBuUyZMsbKlSuNmzdvGnfu3DH+/PNPo3Xr1qme27ZtW+P48eNGYmKi1SXJFStWNLZs2WLExMQY165dMxYsWGC5DPvhy5YzMoPyo9qj1temTRvj6NGjxp07d4xz584ZH3/8seHn52cYhmGULl3a6vfwqCkAdu7cmer96dOnj3HmzBkjKSnpqS9Dr1WrlvHjjz8aFy9eNBISEozIyEhj69atRvfu3S2X80v3L/OfOnWqZbmTJ08aQ4cOtVpX48aNjTVr1hgXL1404uPjjYsXLxrLly83ypUr91S/n8e1jz76yIiJiXnk5fpS+mZQflJ7sB1Xr141EhMTjYiICGPt2rVW0yxIMlq2bGkYhmG88MILmfZZpdEeNLv/7wcAQC7g7u6uc+fOadiwYfrhhx9sXY7FmjVrZBiG3njjDVuXAhMi7ABALjNs2DD16tVLlStXzhaXeVesWFGBgYGqWbPmP055AKQHYQcAAJgaV2MBAABTI+wAAABTI+wAAABTI+wAAABTY1LB/0/x4sXTfIdeAABgW25ubrp8+fITlyHs6H7QeZo7KwMAgOynRIkSTww8hB3JskenRIkS7N0BACCHcHNz06VLl/7xbzdh5yGxsbGEHQAATIYTlAEAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKkRdgAAgKk52roA2NY9Y52tS8AzZG/X1tYlAMAzx54dAABgaoQdAABgaoQdAABgaoQdAABgaoQdAABgaoQdAABgaoQdAABgaoQdAABgaoQdAABgaoQdAABgatwuAgBMitvB5C7cDubx2LMDAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMLduEneHDh8swDE2fPt3S5+zsrDlz5ujGjRuKjY3Vr7/+qiJFilg9r1SpUlq/fr3i4uIUERGhr7/+Wg4ODs+6fAAAkE1li7Dz4osv6r333tOxY8es+qdPn662bduqc+fO8vX1VfHixbV69WrLuL29vTZs2CAnJyc1aNBAPXv2lJ+fn8aPH/+sNwEAAGRTNg87rq6uWr58ud59911FRUVZ+t3d3dWnTx8NGTJEO3fu1JEjR9SrVy81bNhQdevWlSS1aNFClStX1jvvvKNjx45p8+bN+uyzz/TBBx8oT548ttokAACQjdg87MydO1cbNmzQ9u3brfp9fHzk5OSkbdu2WfpOnjypsLAw1a9fX5JUv359BQYG6tq1a5Zl/P395eHhoSpVqjz2NZ2cnOTm5mbVAACAOTna8sW7du2q2rVrq06dOqnGvLy8lJCQoOjoaKv+iIgIeXl5WZaJiIhINf5g7HFGjhypsWPHZrB6AACQE9hsz07JkiU1c+ZMdevWTQkJCc/0tSdOnCh3d3dLK1GixDN9fQAA8OzYLOz4+PioaNGiOnLkiJKSkpSUlKRGjRpp4MCBSkpKUkREhJydneXh4WH1vKJFi+rq1auSpKtXr6po0aKpxh+MPU5iYqJiY2OtGgAAMCebhZ3t27eratWqqlmzpqX997//1fLly1WzZk0dOnRIiYmJatq0qeU55cuXV+nSpRUQECBJCggIULVq1VS4cGHLMs2bN1d0dLSCgoKe+TYBAIDsx2bn7Ny+fVsnTpyw6ouLi1NkZKSlf+HChZo2bZpu3rypmJgYzZ49W/v379eBAwckSVu2bFFQUJCWLVumYcOGycvLS59//rnmzp2rxMTEZ75NAAAg+7HpCcr/ZPDgwbp3755WrVolZ2dn+fv7q3///pbxe/fuqU2bNpo/f74CAgIUFxenJUuWaPTo0TasGgAAZCd2kgxbF2Frbm5uiomJkbu7e647f+eesc7WJeAZsrdra+sS8Azx+c5dcuPn+2n/ftt8nh0AAICsRNgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmZtOw069fPx07dkzR0dGKjo7W/v371apVK8u4s7Oz5syZoxs3big2Nla//vqrihQpYrWOUqVKaf369YqLi1NERIS+/vprOTg4POtNAQAA2ZRNw87Fixc1YsQI+fj46MUXX9SOHTu0du1aVa5cWZI0ffp0tW3bVp07d5avr6+KFy+u1atXW55vb2+vDRs2yMnJSQ0aNFDPnj3l5+en8ePH22qTAABANmMnybB1EQ+LjIzUxx9/rF9//VXXr1/X22+/rVWrVkmSKlSooJCQENWrV08HDhxQq1attH79ehUvXlzXrl2TJL333nuaNGmSChcurKSkpKd6TTc3N8XExMjd3V2xsbFZtm3Z0T1jna1LwDNkb9fW1iXgGeLznbvkxs/30/79zjbn7Njb26tr165ydXVVQECAfHx85OTkpG3btlmWOXnypMLCwlS/fn1JUv369RUYGGgJOpLk7+8vDw8PValS5bGv5eTkJDc3N6sGAADMyeZhp2rVqoqNjVVCQoK++eYbdezYUcHBwfLy8lJCQoKio6Otlo+IiJCXl5ckycvLSxEREanGH4w9zsiRIxUTE2Nply5dyuStAgAA2YXNw87JkydVs2ZN1a1bV/Pnz9eSJUtUqVKlLH3NiRMnyt3d3dJKlCiRpa8HAABsJ81hx9HRUdu2bVO5cuUypYCkpCSdPXtWR44c0SeffKJj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cuPn+2n/fts07GQXhB3kFrnxf4a5GZ/v3CU3fr6zbJ4dAACAnISwAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATM2mYeeVV17R77//rkuXLskwDLVv3z7VMuPGjdPly5d1584dbd26VeXKlbMaL1iwoH788UdFR0crKipK33//vVxdXZ/VJgAAgGzOpmHH1dVVx44d0wcffPDI8WHDhmngwIHq16+f6tatq7i4OPn7+8vZ2dmyzPLly1WlShU1b95cbdq00auvvqpvv/32WW0CAADI5uwkGbYuQpIMw1CHDh20du1aS9/ly5c1depUTZ06VZLk7u6uiIgI+fn5acWKFapYsaKCg4P14osv6vDhw5Kkli1bauPGjSpZsqSuXLnyVK/t5uammJgYubu7KzY2NvM3Lhu7Z6yzdQl4huzt2tq6BDxDfL5zl9z4+X7av9+Oz7CmNClTpoyKFSumbdu2WfpiYmJ04MAB1a9fXytWrFD9+vUVFRVlCTqStG3bNt27d09169bVb7/99sh1Ozk5We0dcnNzy7LtALI7FxcXFSpUSHZ2drYuBel07949XblyRcnJybYuBciWsm3Y8fLykiRFRERY9UdERFjGvLy8dO3aNavxlJQU3bx507LMo4wcOVJjx47N3IKBHMbOzk69evVSo0aNbF0KMkF8fLxGjRql69ev27oUINvJtmEnK02cOFHTpk2zPHZzc9OlS5dsWBHw7PXq1Uu+vr5a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", - "text/plain": [ - "
" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Summary\n", + "In this example, IDAES Process Costing Framework methods were applied to two HDA flowsheets for capital cost estimation. The costing blocks calls showcased multiple methods to define unit costing, demonstrating the flexibility and best practice of the costing framework. In the basic examples, the two-flash HDA did not include costing and the distillation HDA estimated a reactor capital cost comprising 3.3% of the total plant cost (TPC). With more rigorous costing, IDAES obtained total capital costs of 8.5% TPC (two flash HDA) and 9.6% (distillation HDA) and better modeled the impact of equipment cost on process economics. As printed above, the IDAES Process Costing Framework confirmed that replacing the second flash drum with a distillation column results in increased equipment costs, increased production and decreased cost per unit product." ] - }, - "metadata": { - "filenames": { - "image/png": "C:\\Users\\dkgun\\src\\dangunter\\examples\\idaes_examples\\notebooks\\_build\\jupyter_execute\\docs\\flowsheets\\hda_flowsheet_with_costing_doc_25_2.png" - } - }, - "output_type": "display_data" } - ], - "source": [ - "# Compare total costs (capital costs and operating costs)\n", - "\n", - "two_flash_totcost = {\n", - " \"capital\": sum(two_flash_capcost[idx] for idx in two_flash_capcost),\n", - " \"operating\": value(m.fs.operating_cost) / 1e3,\n", - "}\n", - "distillation_totcost = {\n", - " \"capital\": sum(distillation_capcost[idx] for idx in distillation_capcost),\n", - " \"operating\": value(n.fs.operating_cost) / 1e3,\n", - "}\n", - "\n", - "two_flash_totdf = pd.DataFrame(\n", - " list(two_flash_totcost.items()), columns=[\"Costs\", \"Two Flash\"]\n", - ").set_index(\"Costs\")\n", - "distillation_totdf = pd.DataFrame(\n", - " list(distillation_totcost.items()), columns=[\"Costs\", \"Distillation\"]\n", - ").set_index(\"Costs\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "totcosts = two_flash_totdf.add(distillation_totdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(totcosts) # view dataframe before plotting\n", - "\n", - "totplot = totcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Total Plant Cost (TPC)\", ylabel=\"$1000/year\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's compare the total costs on a production basis. This will account for the greater efficiency provided by the distillation column relative to the less-expensive second flash unit:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Two flash case over one year: $459K / 4477 kmol benzene = $102.45 per kmol benzene produced\n", - "Distillation case over one year: $473K / 5108 kmol benzene = $92.63 per kmol benzene produced\n" - ] + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" } - ], - "source": [ - "two_flash_cost = value(1e3 * sum(two_flash_totcost[idx] for idx in two_flash_totcost))\n", - "two_flash_prod = value(\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] * 365 * 24 * 3600\n", - ")\n", - "distillation_cost = value(\n", - " 1e3 * sum(distillation_totcost[idx] for idx in distillation_totcost)\n", - ")\n", - "distillation_prod = value(n.fs.D101.condenser.distillate.flow_mol[0] * 365 * 24 * 3600)\n", - "\n", - "print(\n", - " f\"Two flash case over one year: ${two_flash_cost/1e3:0.0f}K / {two_flash_prod/1e3:0.0f} kmol benzene = ${two_flash_cost/(two_flash_prod/1e3):0.2f} per kmol benzene produced\"\n", - ")\n", - "print(\n", - " f\"Distillation case over one year: ${distillation_cost/1e3:0.0f}K / {distillation_prod/1e3:0.0f} kmol benzene = ${distillation_cost/(distillation_prod/1e3):0.2f} per kmol benzene produced\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Summary\n", - "In this example, IDAES Process Costing Framework methods were applied to two HDA flowsheets for capital cost estimation. The costing blocks calls showcased multiple methods to define unit costing, demonstrating the flexibility and best practice of the costing framework. In the basic examples, the two-flash HDA did not include costing and the distillation HDA estimated a reactor capital cost comprising 3.3% of the total plant cost (TPC). With more rigorous costing, IDAES obtained total capital costs of 8.5% TPC (two flash HDA) and 9.6% (distillation HDA) and better modeled the impact of equipment cost on process economics. As printed above, the IDAES Process Costing Framework confirmed that replacing the second flash drum with a distillation column results in increased equipment costs, increased production and decreased cost per unit product." - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.5" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_test.ipynb b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_test.ipynb index 1d02bf6f..1cc0ff85 100644 --- a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_test.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_test.ipynb @@ -1,562 +1,2381 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [ + "header", + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# HDA Flowsheet Costing\n", + "Maintainer: Brandon Paul \n", + "Author: Brandon Paul \n", + "Updated: 2023-06-01 \n", + "\n", + "\n", + "## Note\n", + "\n", + "This example will demonstrate adding capital and operating costs to the two HDA examples, the basic [HDA with Flash](../tut/hda_flowsheet_solution_test.ipynb) and a comparison with the HDA with Distillation.\n", + "\n", + "\n", + "## Learning outcomes\n", + "\n", + "- Import external pre-built steady-state flowsheets using the IDAES unit model library\n", + "- Define and add costing blocks using the IDAES Process Costing Framework\n", + "- Formulate and solve a process economics optimization problem\n", + " - Defining an objective function\n", + " - Setting variable bounds\n", + " - Adding additional constraints \n", + "\n", + "\n", + "## Problem Statement\n", + "\n", + "Hydrodealkylation is a chemical reaction that often involves reacting\n", + "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", + "simpler aromatic hydrocarbon devoid of functional groups. In this\n", + "example, toluene will be reacted with hydrogen gas at high temperatures\n", + " to form benzene via the following reaction:\n", + "\n", + "**C6H5CH3 + H2 \u2192 C6H6 + CH4**\n", + "\n", + "\n", + "This reaction is often accompanied by an equilibrium side reaction\n", + "which forms diphenyl, which we will neglect for this example.\n", + "\n", + "This example is based on the 1967 AIChE Student Contest problem as\n", + "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", + "McGraw-Hill.\n", + "\n", + "Users may refer to the prior examples linked at the top of this notebook for detailed process descriptions of the two HDA configurations. As before, the properties required for this module are defined in\n", + "\n", + "- `hda_ideal_VLE.py`\n", + "- `idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE`\n", + "- `hda_reaction.py`\n", + "\n", + "Additionally, we will be importing externally-defined flowsheets for the two HDA configurations from\n", + "\n", + "- `hda_flowsheets_for_costing_notebook.py`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import and run HDA Flowsheets\n", + "First, we will generate solved flowsheets for each HDA model. The external scripts build and set inputs for the flowsheets, initialize unit models and streams, and solve the flowsheets before returning the model objects. Note that the HDA flowsheets contain all unit models and stream connections, and no costing equations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The flowsheet utilizes the Wegstein method to iteratively solve circular dependencies such as recycle streams, and is intended to approach a feasible solution. As such, the calls below will fail to converge after 3 iterations and pass to IPOPT to obtain an optimal solution as expected:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "fs.s03\n", + "fs.H101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n", + "2026-07-22 11:48:38 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "Solving flowsheet...\n", + "\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=5000\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1031\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 934\n", + "\n", + "Total number of variables............................: 340\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 146\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 340\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.60e+04 0.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 8.69e+03 1.42e+03 -1.0 2.00e+04 - 9.71e-01 4.67e-01H 1\n", + " 2 0.0000000e+00 3.05e+03 1.56e+03 -1.0 1.60e+04 - 9.79e-01 4.90e-01h 1\n", + " 3 0.0000000e+00 1.58e+03 1.55e+05 -1.0 1.40e+04 - 9.90e-01 4.99e-01h 1\n", + " 4 0.0000000e+00 5.49e+02 8.87e+08 -1.0 8.42e+03 - 1.00e+00 9.57e-01h 1\n", + " 5 0.0000000e+00 4.25e+03 2.87e+10 -1.0 8.02e+02 - 1.00e+00 9.90e-01h 1\n", + " 6 0.0000000e+00 2.25e+03 1.51e+10 -1.0 8.39e+00 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 2.27e+01 1.40e+08 -1.0 2.45e-03 - 1.00e+00 1.00e+00f 1\n", + " 8 0.0000000e+00 2.45e-03 1.23e+04 -1.0 2.39e-05 - 1.00e+00 1.00e+00h 1\n", + " 9 0.0000000e+00 2.24e-08 4.65e-01 -2.5 9.06e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 0.0000000e+00 2.24e-08 1.41e+05 -5.7 1.38e-07 - 1.00e+00 5.00e-01h 2\n", + " 11 0.0000000e+00 7.45e-09 5.56e-03 -5.7 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 12 0.0000000e+00 7.45e-09 2.47e-09 -5.7 9.00e-08 - 1.00e+00 1.00e+00h 1\n", + " 13 0.0000000e+00 2.24e-08 5.06e-07 -7.0 1.38e-07 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 13\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "Constraint violation....: 5.8207660913467407e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593319938534624e-14 2.8593319938534624e-14\n", + "Complementarity.........: 9.0909090909115134e-08 9.0909090909115134e-08\n", + "Overall NLP error.......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "\n", + "\n", + "Number of objective function evaluations = 17\n", + "Number of objective gradient evaluations = 14\n", + "Number of equality constraint evaluations = 17\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 14\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 13\n", + "Total seconds in IPOPT = 0.018\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Complete.\n", + "\n" + ] + } + ], + "source": [ + "# Source file for prebuilt flowsheets\n", + "from hda_flowsheets_for_costing_notebook import hda_with_flash\n", + "\n", + "# Build hda model with second flash unit and return model object\n", + "m = hda_with_flash(tee=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## IDAES Process Costing Framework\n", + "IDAES provides a library of capital costing correlations based on those in the following source:\n", + "\n", + "*Process and Product Design Principles: Synthesis, Analysis, and Evaluation*. Seider, Seader, Lewin, Windagdo, 3rd Ed. John Wiley and Sons Chapter 22. Cost Accounting and Capital Cost Estimation 22.2 Cost Indexes and Capital Investment.\n", + "\n", + "Currently, IDAES supports calculation of capital costing for a wide array of unit operations, vesseel sizing and material properties, and specific unit options such as column tray types and heat exchanger configurations. Users may find further information on specific costing methods and options in the IDAES Process Costing Framework documentation (link pending).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Operating Cost Equations\n", + "Before adding capital costing blocks, we will add operating cost equations taken from the basic [HDA with Flash](../tut/hda_flowsheet_solution_test.ipynb) and the HDA with Distillation examples. The examples assume constant cooling and heating coefficients over an annual cost basis. The IDAES Generic Costing Framework does not currently support variable cost calculations." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Required imports\n", + "from pyomo.environ import Expression\n", + "\n", + "# Operating costs for HDA with second flash (model m)\n", + "m.fs.cooling_cost = Expression(\n", + " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", + ")\n", + "m.fs.heating_cost = Expression(\n", + " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", + ")\n", + "m.fs.operating_cost = Expression(\n", + " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Capital Costing\n", + "Below, we will add add capital costing blocks to the imported flowsheets and evaluate the economic impact of replacing the second Flash with a Distillation column. First, let's import and define the main flowsheet costing block:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Import costing methods - classes, heaters, vessels, compressors, columns\n", + "from idaes.models.costing.SSLW import (\n", + " SSLWCosting,\n", + " SSLWCostingData,\n", + ")\n", + "from idaes.core import UnitModelCostingBlock\n", + "\n", + "# Costing block\n", + "m.fs.costing = SSLWCosting()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will build the relevant costing blocks for the equipment we wish to cost. Note how the costing block, methods and flags are passed as arguments in the costing block call itself. Each unit model will have a single costing block, but each flowsheet model (m and n) will also have a single costing block for flowsheet-level properties.\n", + "\n", + "Users should note that IDAES costing methods support a wide array of heating sources (e.g. fired, steam boiler, hot water) and do not support direct capital costing of coolers. If users wish to cost Heater units acting as coolers, it is necessary to cost a \"dummy\" [0D shell and tube exchanger](https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/heat_exchanger.html) with appropriate aliased hot stream properties and proper cooling water properties. This is not demonstrated here, as the HDA examples take advantage of Flash and Condenser operations to recover liquid product.\n", + "\n", + "Capital costing is independent of unit model connections, and building cost equations may be done piecewise in this fashion. Default options are passed explicitly to demonstrate proper syntax and usage. Now that all required properties are defined, let's cost our models connecting costing blocks, methods and unit models in each flowsheet." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Flexibility of Costing Block Definitions\n", + "IDAES supports many ways to define batches of costing blocks, and several are shown in the example. Users may employ whichever method fits their modeling needs for explicit or concise code. In the code below, note how the unit model itself is never passed to the costing method; when the full model is executed, the costing block will automatically connect its parent block with child equation blocks.\n", + "\n", + "`Compressor` unit models with isothermal or adiabatic thermodynamics are too simple to cost and are therefore excluded from the economic analysis." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define costing for the heater unit:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from idaes.models.costing.SSLW import (\n", + " HeaterMaterial,\n", + " HeaterSource,\n", + ")\n", + "\n", + "# Costing for heater - m.fs.H101\n", + "m.fs.H101.costing = UnitModelCostingBlock(\n", + " flowsheet_costing_block=m.fs.costing,\n", + " costing_method=SSLWCostingData.cost_fired_heater,\n", + " costing_method_arguments={\n", + " \"material_type\": HeaterMaterial.CarbonSteel,\n", + " \"heat_source\": HeaterSource.Fuel,\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The costing module provides a `unit_mapping` dictionary linking generic unit model classes with recommended costing methods. In this example, StoichiometricReactor and Flash vessels utilize different vessel costing methods with similar arguments. The diameter and length attributes need to exist in order to cost vessel sizing and material requirements, and we add them if they don't exist already. The `unit_mapping` method provides an opportunity to automatically select the correct vessel orientation (vertical or horizontal) based on the unit type; passing a `StoichiometricReactor` or `PFR` class object will call the `cost_horizontal_vessel` method, while passing a `Flash` or `CSTR` class object will call the `cost_vertical_vessel` method.\n", + "\n", + "All vessels are assigned costing succinctly via a loop below - users may define each block individually if desired:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from idaes.models.costing.SSLW import (\n", + " VesselMaterial,\n", + " TrayType,\n", + " TrayMaterial,\n", + ")\n", + "\n", + "from idaes.core.util.constants import Constants\n", + "from pyomo.environ import Var, Constraint, units as pyunits, Param, value\n", + "from idaes.models.unit_models import StoichiometricReactor, Flash\n", + "\n", + "# Map unit models to unit classes\n", + "# Will pass to unit_mapping which calls costing methods based on unit class\n", + "unit_class_mapping = {\n", + " m.fs.R101: StoichiometricReactor,\n", + " m.fs.F101: Flash,\n", + " m.fs.F102: Flash,\n", + "}\n", + "\n", + "# Costing for vessels - m.fs.R101, m.fs.F101, m.fs.F102\n", + "\n", + "# Loop over units\n", + "for unit in [m.fs.R101, m.fs.F101, m.fs.F102]:\n", + " # Get correct unit class for unit model\n", + " unit_class = unit_class_mapping[unit]\n", + "\n", + " # Add dimension variables and constraint if they don't exist\n", + " if not hasattr(unit, \"diameter\"):\n", + " unit.diameter = Var(initialize=1, units=pyunits.m)\n", + " if not hasattr(unit, \"length\"):\n", + " unit.length = Var(initialize=1, units=pyunits.m)\n", + " if hasattr(unit, \"volume\"): # if volume exists, set diameter from volume\n", + " unit.volume_eq = Constraint(\n", + " expr=unit.volume[0] == unit.length * unit.diameter**2 * 0.25 * Constants.pi\n", + " )\n", + " else: # fix diameter directly\n", + " unit.diameter.fix(0.2214 * pyunits.m)\n", + " # Either way, fix L/D to calculate L from D\n", + " unit.L_over_D = Constraint(expr=unit.length == 3 * unit.diameter)\n", + "\n", + " # Define vessel costing\n", + " unit.costing = UnitModelCostingBlock(\n", + " flowsheet_costing_block=unit.parent_block().costing, # e.g. m.fs.R101.costing\n", + " costing_method=SSLWCostingData.unit_mapping[\n", + " unit_class\n", + " ], # e.g. cost_vertical_vessel()\n", + " costing_method_arguments={\n", + " \"material_type\": VesselMaterial.CarbonSteel,\n", + " \"shell_thickness\": 1.25 * pyunits.inch,\n", + " },\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solve Flowsheet Costing Blocks\n", + "Now, we may solve the full flowsheet for all costing blocks:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Define solver\n", + "from idaes.core.solvers import get_solver\n", + "\n", + "solver = get_solver(\"ipopt_v2\", options={\"max_iter\": 500})\n", + "\n", + "# Check that the degrees of freedom is zero\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "\n", + "assert degrees_of_freedom(m) == 0" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.14.20: linear_solver=\"ma57\"\n", + "max_iter=500\n", + "nlp_scaling_method=\"gradient-based\"\n", + "tol=1e-06\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 604\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 569\n", + "\n", + "Total number of variables............................: 160\n", + " variables with only lower bounds: 10\n", + " variables with lower and upper bounds: 38\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 160\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.00e+05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (6534)\n", + " 1 0.0000000e+00 8.81e+04 5.45e+03 -1.0 9.27e+04 - 2.62e-01 1.20e-01h 1\n", + " 2 0.0000000e+00 6.34e+04 2.46e+03 -1.0 8.16e+04 - 9.83e-01 2.87e-01h 1\n", + " 3 0.0000000e+00 3.40e+04 1.76e+03 -1.0 5.81e+04 - 4.59e-01 4.86e-01h 1\n", + " 4 0.0000000e+00 2.33e+04 9.17e+04 -1.0 2.99e+04 - 7.04e-01 5.09e-01h 1\n", + " 5 0.0000000e+00 1.13e+04 7.52e+08 -1.0 1.47e+04 - 8.02e-01 9.65e-01h 1\n", + "Reallocating memory for MA57: lfact (7452)\n", + " 6 0.0000000e+00 5.50e+03 3.83e+08 -1.0 8.18e+02 - 9.90e-01 6.10e-01h 1\n", + " 7 0.0000000e+00 5.23e+03 3.45e+08 -1.0 3.84e+02 - 1.00e+00 5.07e-02h 1\n", + "Reallocating memory for MA57: lfact (8076)\n", + " 8 0.0000000e+00 5.22e+03 7.30e+08 -1.0 3.70e+02 - 1.00e+00 5.85e-04h 1\n", + " 9r 0.0000000e+00 5.22e+03 1.00e+03 2.3 0.00e+00 - 0.00e+00 3.66e-07R 5\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10r 0.0000000e+00 6.37e+04 2.29e+04 2.3 2.43e+07 - 1.50e-03 9.91e-04f 1\n", + " 11r 0.0000000e+00 1.51e+04 1.09e+05 2.3 2.98e+07 - 1.34e-01 2.58e-03f 1\n", + " 12r 0.0000000e+00 3.92e+04 1.08e+05 2.3 8.59e+07 - 8.37e-03 1.46e-02f 1\n", + " 13r 0.0000000e+00 1.67e+05 1.08e+05 2.3 5.23e+06 - 5.83e-03 9.06e-02f 1\n", + " 14r 0.0000000e+00 4.67e+05 1.05e+05 2.3 1.18e+07 - 2.42e-02 9.08e-02f 1\n", + " 15r 0.0000000e+00 4.64e+05 1.05e+05 2.3 5.75e+06 - 1.97e-03 6.57e-03h 1\n", + " 16r 0.0000000e+00 4.63e+05 9.23e+04 2.3 1.50e+04 -4.0 1.25e-01 1.34e-03h 1\n", + " 17r 0.0000000e+00 6.08e+05 8.46e+04 2.3 5.32e+06 - 8.37e-02 3.04e-01f 1\n", + " 18r 0.0000000e+00 5.71e+05 5.77e+04 2.3 1.87e+06 - 3.20e-01 1.38e-01f 1\n", + " 19r 0.0000000e+00 4.10e+05 5.27e+04 2.3 4.12e+06 - 9.00e-02 3.37e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r 0.0000000e+00 3.86e+05 4.93e+04 2.3 1.63e+04 -3.6 6.50e-02 5.85e-02f 1\n", + " 21r 0.0000000e+00 3.60e+05 4.51e+04 2.3 7.48e+03 -3.1 8.38e-02 6.63e-02h 1\n", + " 22r 0.0000000e+00 3.64e+05 4.08e+04 2.3 4.06e+06 - 9.58e-02 7.04e-02f 1\n", + " 23r 0.0000000e+00 3.86e+05 1.88e+05 2.3 5.59e+06 - 1.68e-01 1.49e-01f 1\n", + " 24r 0.0000000e+00 3.86e+05 1.88e+05 2.3 1.12e+02 4.7 1.81e-03 1.57e-03h 1\n", + " 25r 0.0000000e+00 3.86e+05 1.91e+05 2.3 1.55e+02 4.2 2.71e-03 1.11e-03h 1\n", + " 26r 0.0000000e+00 3.85e+05 1.86e+05 2.3 1.56e+02 3.7 8.21e-04 3.62e-03h 1\n", + " 27r 0.0000000e+00 3.85e+05 3.16e+05 2.3 1.55e+02 5.1 1.83e-02 6.41e-04h 1\n", + " 28r 0.0000000e+00 3.82e+05 3.30e+05 2.3 1.55e+02 4.6 1.40e-02 1.11e-02h 1\n", + " 29r 0.0000000e+00 3.81e+05 7.08e+05 2.3 1.53e+02 5.0 2.85e-02 4.20e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30r 0.0000000e+00 3.72e+05 7.46e+05 2.3 1.53e+02 4.5 4.86e-02 3.45e-02h 1\n", + " 31r 0.0000000e+00 3.67e+05 1.89e+06 2.3 1.47e+02 5.0 1.12e-01 2.04e-02h 1\n", + " 32r 0.0000000e+00 3.24e+05 1.59e+06 2.3 1.44e+02 4.5 1.96e-01 1.79e-01h 1\n", + " 33r 0.0000000e+00 3.23e+05 1.58e+06 2.3 1.19e+02 4.0 4.52e-03 5.61e-03h 1\n", + " 34r 0.0000000e+00 2.94e+05 1.59e+06 2.3 1.18e+02 4.4 3.45e-01 1.47e-01h 1\n", + " 35r 0.0000000e+00 2.80e+05 1.53e+06 2.3 1.01e+02 4.0 1.38e-01 8.76e-02h 1\n", + " 36r 0.0000000e+00 2.52e+05 1.66e+06 2.3 9.17e+01 4.4 3.38e-01 1.83e-01h 1\n", + " 37r 0.0000000e+00 2.39e+05 1.55e+06 2.3 7.50e+01 3.9 9.13e-01 1.05e-01h 1\n", + " 38r 0.0000000e+00 2.13e+05 1.24e+06 2.3 6.72e+01 3.4 5.58e-01 2.28e-01h 1\n", + " 39r 0.0000000e+00 1.95e+05 1.05e+06 2.3 5.18e+01 3.9 1.00e+00 2.15e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40r 0.0000000e+00 1.28e+05 2.34e+05 2.3 4.08e+01 3.4 5.49e-01 1.00e+00h 1\n", + " 41r 0.0000000e+00 1.28e+05 2.87e+05 2.3 8.85e-01 2.9 5.24e-01 9.02e-01f 1\n", + " 42r 0.0000000e+00 1.28e+05 1.76e+05 2.3 3.90e-01 4.2 3.08e-01 9.59e-01f 1\n", + " 43r 0.0000000e+00 1.28e+05 5.03e+04 2.3 1.25e-01 3.8 3.19e-01 1.00e+00f 1\n", + " 44r 0.0000000e+00 1.28e+05 4.94e+04 2.3 4.82e+00 3.3 1.85e-02 1.19e-01f 2\n", + " 45r 0.0000000e+00 1.28e+05 1.37e+04 2.3 3.62e-01 3.7 8.33e-01 1.00e+00f 1\n", + " 46r 0.0000000e+00 1.28e+05 7.07e+03 1.6 5.21e-01 3.2 8.97e-01 1.00e+00f 1\n", + " 47r 0.0000000e+00 1.29e+05 5.44e+02 1.6 9.53e-01 2.8 8.34e-01 8.12e-01f 1\n", + " 48r 0.0000000e+00 1.29e+05 8.91e+02 0.9 2.85e+00 2.3 4.12e-01 2.43e-01f 1\n", + " 49r 0.0000000e+00 1.30e+05 6.99e+02 0.9 8.46e+00 1.8 7.74e-01 2.05e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50r 0.0000000e+00 1.31e+05 3.95e+04 0.9 2.41e+01 1.3 1.00e+00 1.51e-01f 1\n", + " 51r 0.0000000e+00 1.30e+05 4.66e+04 0.9 7.23e+01 0.8 1.00e+00 5.24e-02f 1\n", + " 52r 0.0000000e+00 1.18e+05 3.45e+04 0.9 2.17e+02 0.4 6.96e-01 1.67e-01f 1\n", + " 53r 0.0000000e+00 1.17e+05 1.74e+04 0.9 6.50e+02 -0.1 1.43e-01 1.50e-02f 1\n", + " 54r 0.0000000e+00 1.17e+05 4.23e+04 0.9 1.94e+03 -0.6 6.50e-01 3.25e-02f 1\n", + " 55r 0.0000000e+00 1.18e+05 5.54e+04 0.9 3.69e+03 -1.1 4.70e-01 9.48e-03f 1\n", + " 56r 0.0000000e+00 1.25e+05 2.75e+04 0.9 1.01e+02 -1.5 7.89e-01 1.78e-01f 1\n", + " 57r 0.0000000e+00 1.28e+05 2.68e+04 0.9 9.57e+01 -2.0 9.34e-01 1.60e-01f 1\n", + " 58r 0.0000000e+00 1.37e+05 5.37e+02 0.9 2.51e+02 -2.5 1.00e+00 6.23e-01f 1\n", + " 59r 0.0000000e+00 1.40e+05 1.78e+04 0.2 7.53e+02 -3.0 4.51e-01 6.22e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60r 0.0000000e+00 1.40e+05 1.99e+03 0.2 2.25e+03 -3.4 6.57e-01 3.90e-01f 1\n", + " 61r 0.0000000e+00 1.40e+05 6.25e+04 0.2 8.45e+02 -3.0 1.00e+00 2.93e-01f 1\n", + " 62r 0.0000000e+00 1.40e+05 4.84e+04 0.2 2.48e+03 -3.5 1.00e+00 2.59e-01f 1\n", + " 63r 0.0000000e+00 1.40e+05 9.09e+04 0.2 8.10e+02 -4.0 5.18e-01 4.12e-02f 1\n", + " 64r 0.0000000e+00 1.40e+05 4.52e+03 0.2 3.19e+02 -3.6 5.90e-01 8.39e-01f 1\n", + " 65r 0.0000000e+00 1.40e+05 9.20e+03 0.2 8.45e+02 -4.0 2.58e-01 3.11e-01f 1\n", + " 66r 0.0000000e+00 1.40e+05 9.35e+02 0.2 2.32e+03 -4.5 9.50e-02 5.05e-01f 1\n", + " 67r 0.0000000e+00 1.40e+05 1.80e+03 0.2 3.94e+03 -5.0 1.00e+00 6.61e-02f 1\n", + " 68r 0.0000000e+00 1.40e+05 2.93e+03 0.2 4.85e+03 -5.5 9.99e-01 2.84e-01f 1\n", + " 69r 0.0000000e+00 1.38e+05 6.05e+03 0.2 6.81e+03 -5.9 1.00e+00 2.40e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70r 0.0000000e+00 1.37e+05 1.78e+03 0.2 2.85e+03 -5.5 1.00e+00 1.00e+00f 1\n", + " 71r 0.0000000e+00 1.34e+05 1.31e+03 0.2 8.14e+03 -6.0 3.19e-01 3.05e-01f 1\n", + " 72r 0.0000000e+00 1.31e+05 1.83e+03 0.2 2.65e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 73r 0.0000000e+00 1.28e+05 3.42e+03 0.2 1.45e+04 -6.0 1.00e+00 2.70e-01f 1\n", + " 74r 0.0000000e+00 1.24e+05 1.09e+01 0.2 4.06e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 75r 0.0000000e+00 1.05e+05 7.56e+03 -0.5 5.64e+04 -6.1 2.15e-01 3.59e-01f 1\n", + " 76r 0.0000000e+00 1.05e+05 1.79e+04 -0.5 2.46e+03 -4.8 5.42e-01 1.26e-01f 1\n", + " 77r 0.0000000e+00 1.05e+05 2.30e+04 -0.5 9.93e+03 -5.2 1.04e-02 6.09e-02f 1\n", + " 78r 0.0000000e+00 1.05e+05 1.44e+03 -0.5 2.90e+03 -4.8 1.16e-01 1.32e-02f 1\n", + " 79r 0.0000000e+00 1.04e+05 8.21e+04 -0.5 9.44e+03 -5.3 4.02e-02 1.19e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80r 0.0000000e+00 1.04e+05 4.46e+03 -0.5 1.93e+03 -4.9 2.08e-01 2.98e-02f 1\n", + " 81r 0.0000000e+00 9.40e+04 1.37e+05 -0.5 1.15e+04 -5.3 5.49e-03 2.67e-01f 1\n", + " 82r 0.0000000e+00 9.39e+04 1.21e+05 -0.5 2.56e+03 -4.9 3.04e-01 9.74e-03f 1\n", + " 83r 0.0000000e+00 9.25e+04 1.08e+05 -0.5 4.97e+03 -5.4 1.59e-01 1.20e-01f 1\n", + " 84r 0.0000000e+00 9.25e+04 1.35e+05 -0.5 8.51e+03 -5.9 5.44e-01 3.08e-02f 1\n", + " 85r 0.0000000e+00 1.04e+05 1.06e+05 -0.5 1.26e+04 -6.3 1.73e-01 4.10e-01f 1\n", + " 86r 0.0000000e+00 1.08e+05 1.45e+05 -0.5 2.50e+04 -6.8 1.23e-01 7.63e-02f 1\n", + " 87r 0.0000000e+00 1.07e+05 1.40e+05 -0.5 4.68e+02 -2.8 3.12e-02 1.16e-01h 1\n", + " 88r 0.0000000e+00 1.07e+05 1.34e+05 -0.5 1.25e+02 -2.4 1.37e-01 6.14e-02h 1\n", + " 89r 0.0000000e+00 1.05e+05 1.21e+05 -0.5 6.38e+01 -1.9 4.82e-02 1.54e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r 0.0000000e+00 1.04e+05 1.11e+05 -0.5 2.62e+01 -1.5 9.28e-02 1.14e-01h 1\n", + " 91r 0.0000000e+00 1.02e+05 8.74e+04 -0.5 2.58e+01 -2.0 1.72e-01 2.50e-01h 1\n", + " 92r 0.0000000e+00 1.02e+05 7.56e+04 -0.5 2.13e+01 -1.6 3.40e-01 1.09e-01f 1\n", + " 93r 0.0000000e+00 1.02e+05 5.81e+04 -0.5 9.06e+00 -2.0 6.37e-01 2.34e-01h 1\n", + " 94r 0.0000000e+00 1.02e+05 3.30e+04 -0.5 2.09e+01 -2.5 1.00e+00 4.49e-01h 1\n", + " 95r 0.0000000e+00 1.01e+05 2.02e+03 -0.5 9.58e+01 -3.0 4.65e-01 8.13e-01f 1\n", + " 96r 0.0000000e+00 1.02e+05 1.56e+04 -0.5 8.77e+01 -3.5 7.24e-01 1.53e-01f 1\n", + " 97r 0.0000000e+00 1.02e+05 5.99e+03 -0.5 2.31e+02 -3.9 3.97e-01 4.89e-01f 1\n", + " 98r 0.0000000e+00 1.04e+05 4.62e+03 -0.5 4.75e+02 -4.4 6.42e-01 1.95e-01f 1\n", + " 99r 0.0000000e+00 1.04e+05 9.76e+02 -0.5 8.15e+02 -4.9 7.06e-01 6.61e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r 0.0000000e+00 1.05e+05 7.45e+03 -0.5 2.44e+03 -5.4 1.00e+00 1.91e-01f 1\n", + " 101r 0.0000000e+00 1.06e+05 1.94e+03 -0.5 7.23e+02 -4.9 1.00e+00 3.62e-01f 1\n", + " 102r 0.0000000e+00 1.07e+05 7.40e+03 -0.5 1.49e+03 -5.4 1.00e+00 4.66e-01f 1\n", + " 103r 0.0000000e+00 1.08e+05 3.03e+03 -0.5 1.66e+03 -5.9 8.96e-01 8.34e-01f 1\n", + " 104r 0.0000000e+00 1.10e+05 5.48e+02 -0.5 9.38e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 105r 0.0000000e+00 1.10e+05 1.76e+02 -0.5 1.46e+03 -6.0 7.45e-01 1.00e+00f 1\n", + " 106r 0.0000000e+00 1.10e+05 7.27e+01 -0.5 6.32e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 107r 0.0000000e+00 1.11e+05 1.41e+03 -0.5 1.49e+03 -6.0 1.00e+00 9.82e-01f 1\n", + " 108r 0.0000000e+00 1.12e+05 1.04e+03 -0.5 3.05e+03 -6.5 1.00e+00 4.21e-01f 1\n", + " 109r 0.0000000e+00 1.12e+05 3.92e+02 -0.5 7.12e+03 -7.0 8.81e-01 5.45e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110r 0.0000000e+00 1.12e+05 6.27e+02 -0.5 1.40e+04 -7.4 1.00e+00 2.04e-01f 1\n", + " 111r 0.0000000e+00 1.27e+05 1.93e+02 -0.5 2.11e+04 -7.9 7.01e-01 6.92e-01f 1\n", + " 112r 0.0000000e+00 1.51e+05 1.49e+02 -0.5 2.24e+04 -8.4 4.24e-01 4.78e-01f 1\n", + " 113r 0.0000000e+00 1.28e+05 1.63e+01 -0.5 2.40e+04 -8.9 1.00e+00 1.00e+00f 1\n", + " 114r 0.0000000e+00 1.36e+05 3.29e+02 -0.5 4.21e+04 -9.3 6.45e-01 1.00e+00f 1\n", + " 115r 0.0000000e+00 5.01e+05 1.31e+03 -0.5 9.66e+04 -9.8 9.22e-01 1.00e+00h 1\n", + " 116r 0.0000000e+00 8.78e+05 4.66e+02 -0.5 2.96e+05 -10.3 9.46e-01 1.00e+00h 1\n", + " 117r 0.0000000e+00 6.70e+04 4.18e+02 -0.5 9.60e+05 -10.8 1.00e+00 1.00e+00h 1\n", + " 118r 0.0000000e+00 5.21e+04 9.75e+02 -0.5 3.82e+06 -11.3 1.00e+00 7.10e-01f 1\n", + " 119r 0.0000000e+00 5.30e+04 9.97e+02 -0.5 9.41e+06 - 8.43e-02 2.44e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120r 0.0000000e+00 5.40e+04 9.62e+02 -0.5 2.95e+06 - 1.00e+00 1.41e-01f 1\n", + " 121r 0.0000000e+00 5.13e+04 5.63e+01 -0.5 1.96e+05 - 1.00e+00 1.00e+00f 1\n", + " 122r 0.0000000e+00 5.06e+04 7.06e-01 -0.5 1.45e+04 - 1.00e+00 1.00e+00h 1\n", + " 123r 0.0000000e+00 4.48e+04 1.60e+01 -2.9 1.41e+04 - 8.33e-01 7.83e-01f 1\n", + " 124r 0.0000000e+00 7.43e+04 1.23e+02 -2.9 1.09e+05 -9.9 1.51e-01 1.14e-01f 1\n", + " 125r 0.0000000e+00 7.21e+04 3.54e+02 -2.9 1.66e+05 - 1.51e-01 3.48e-02h 1\n", + " 126r 0.0000000e+00 4.03e+04 3.48e+02 -2.9 6.43e+04 - 4.59e-01 5.71e-01f 1\n", + " 127r 0.0000000e+00 9.43e+03 9.62e+01 -2.9 2.75e+04 - 5.72e-01 8.74e-01h 1\n", + " 128r 0.0000000e+00 7.66e+03 2.89e+02 -2.9 4.00e+03 - 7.38e-01 1.00e+00h 1\n", + " 129r 0.0000000e+00 8.78e+02 2.90e+01 -2.9 1.50e+03 - 9.18e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 130r 0.0000000e+00 7.37e+02 1.27e+01 -2.9 1.32e+03 - 1.00e+00 1.00e+00h 1\n", + " 131r 0.0000000e+00 3.66e+02 6.41e+00 -2.9 9.22e+02 - 1.00e+00 1.00e+00h 1\n", + " 132r 0.0000000e+00 8.13e+00 2.77e-02 -2.9 6.19e+01 - 1.00e+00 1.00e+00h 1\n", + " 133r 0.0000000e+00 7.03e+03 1.41e+01 -4.3 5.16e+03 - 7.78e-01 7.77e-01f 1\n", + " 134r 0.0000000e+00 5.08e+03 4.30e+02 -4.3 3.71e+03 - 1.00e+00 7.18e-01h 1\n", + " 135r 0.0000000e+00 2.02e+02 2.79e+01 -4.3 6.26e+02 - 1.00e+00 1.00e+00h 1\n", + " 136r 0.0000000e+00 1.50e+01 2.52e+00 -4.3 1.46e+02 - 1.00e+00 1.00e+00h 1\n", + " 137r 0.0000000e+00 8.83e-01 1.86e-02 -4.3 1.27e+01 - 1.00e+00 1.00e+00h 1\n", + " 138r 0.0000000e+00 7.60e-01 3.09e-05 -4.3 1.51e+00 - 1.00e+00 1.00e+00h 1\n", + " 139 0.0000000e+00 7.60e-01 1.08e+06 -1.0 8.24e+02 - 9.89e-01 7.57e-06h 17\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 140 0.0000000e+00 7.60e-01 1.94e+06 -1.0 8.24e+02 - 9.90e-01 1.89e-06h 19\n", + " 141 0.0000000e+00 2.27e+02 9.80e+05 -1.0 8.24e+02 - 4.96e-01 4.96e-01s 21\n", + " 142r 0.0000000e+00 2.27e+02 1.00e+03 -1.0 0.00e+00 - 0.00e+00 0.00e+00R 1\n", + " 143r 0.0000000e+00 2.20e+02 1.07e+04 -1.0 2.63e+04 - 2.05e-01 5.61e-03f 1\n", + " 144r 0.0000000e+00 2.03e+03 1.87e+03 -1.0 2.78e+04 - 9.30e-01 2.21e-01f 1\n", + " 145r 0.0000000e+00 1.09e+04 2.99e+03 -1.0 1.86e+04 - 3.04e-01 6.48e-01f 1\n", + " 146r 0.0000000e+00 1.30e+04 1.58e+03 -1.0 1.46e+05 - 2.04e-01 3.61e-01f 1\n", + " 147r 0.0000000e+00 1.36e+04 3.08e+02 -1.0 1.18e+04 - 9.12e-01 1.00e+00f 1\n", + " 148r 0.0000000e+00 1.10e+04 2.16e+00 -1.0 4.09e+00 -4.0 1.00e+00 1.00e+00h 1\n", + " 149r 0.0000000e+00 1.22e+04 1.65e+00 -1.7 2.94e+01 -4.5 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 150r 0.0000000e+00 1.31e+04 1.64e+00 -1.7 5.03e+01 -5.0 1.00e+00 1.00e+00f 1\n", + " 151r 0.0000000e+00 1.29e+04 3.23e+00 -1.7 3.50e+01 -5.4 1.00e+00 1.00e+00h 1\n", + " 152r 0.0000000e+00 1.19e+04 5.44e+02 -1.7 3.69e+04 - 1.00e+00 6.74e-01f 1\n", + " 153r 0.0000000e+00 3.43e+03 2.19e+01 -1.7 1.23e+04 - 1.00e+00 1.00e+00h 1\n", + " 154r 0.0000000e+00 2.96e+03 5.24e-01 -1.7 1.78e+03 - 1.00e+00 1.00e+00h 1\n", + " 155r 0.0000000e+00 2.99e+03 2.57e+01 -2.5 1.05e+04 - 8.24e-01 8.54e-01f 1\n", + " 156r 0.0000000e+00 4.83e+03 2.10e+01 -2.5 3.56e+03 - 1.00e+00 9.28e-01h 1\n", + " 157r 0.0000000e+00 1.91e+02 6.11e+00 -2.5 7.38e+02 - 1.00e+00 1.00e+00h 1\n", + " 158r 0.0000000e+00 6.34e+01 3.88e-02 -2.5 7.32e+01 - 1.00e+00 1.00e+00h 1\n", + " 159r 0.0000000e+00 1.16e+04 1.91e+02 -3.8 5.52e+03 - 7.33e-01 9.36e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 160r 0.0000000e+00 8.60e+03 5.01e+02 -3.8 4.56e+03 - 3.35e-01 3.58e-01h 1\n", + " 161r 0.0000000e+00 4.61e+03 2.92e+03 -3.8 2.07e+03 - 8.26e-01 5.26e-01h 1\n", + " 162r 0.0000000e+00 3.60e+02 8.99e+03 -3.8 8.68e+02 - 5.05e-01 1.00e+00h 1\n", + " 163r 0.0000000e+00 1.13e+02 3.07e+02 -3.8 5.08e+02 - 1.00e+00 1.00e+00h 1\n", + " 164r 0.0000000e+00 1.67e+02 3.30e+01 -3.8 6.12e+02 - 1.00e+00 1.00e+00h 1\n", + " 165r 0.0000000e+00 1.22e+01 1.46e-01 -3.8 1.59e+02 - 1.00e+00 1.00e+00h 1\n", + " 166r 0.0000000e+00 2.15e+00 1.25e-03 -3.8 1.80e+01 - 1.00e+00 1.00e+00h 1\n", + " 167r 0.0000000e+00 6.62e+02 3.07e+02 -5.7 2.03e+03 - 9.26e-01 5.74e-01f 1\n", + " 168r 0.0000000e+00 4.94e+02 1.08e+02 -5.7 1.15e+03 - 1.00e+00 7.82e-01h 1\n", + " 169r 0.0000000e+00 4.16e+02 2.06e+02 -5.7 6.08e+02 - 9.82e-01 1.68e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 170r 0.0000000e+00 3.63e+02 1.05e+04 -5.7 1.90e+02 - 1.00e+00 9.40e-01h 1\n", + " 171r 0.0000000e+00 4.94e+03 1.45e+05 -5.7 6.81e+00 - 1.00e+00 9.80e-02h 1\n", + " 172r 0.0000000e+00 5.01e+03 1.47e+05 -5.7 3.34e-01 - 1.00e+00 1.00e+00f 1\n", + " 173r 0.0000000e+00 3.29e+03 2.38e+05 -5.7 4.37e-01 - 1.00e+00 1.00e+00H 1\n", + " 174r 0.0000000e+00 1.30e+03 9.35e+04 -5.7 5.77e-01 - 1.00e+00 2.87e-01h 2\n", + " 175r 0.0000000e+00 2.20e+02 1.60e+04 -5.7 9.32e-02 - 1.00e+00 1.00e+00h 1\n", + " 176r 0.0000000e+00 2.98e+01 2.17e+03 -5.7 3.88e-02 - 9.67e-01 1.00e+00h 1\n", + " 177 0.0000000e+00 2.58e+01 8.80e+06 -1.0 4.77e-01 - 9.90e-01 1.00e+00f 1\n", + " 178 0.0000000e+00 5.64e+00 1.91e+06 -1.0 9.74e-02 - 9.90e-01 1.00e+00h 1\n", + " 179 0.0000000e+00 2.20e-04 3.75e+03 -1.0 5.06e-06 - 9.92e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 180 0.0000000e+00 7.45e-09 1.06e-02 -2.5 1.31e-07 - 1.00e+00 1.00e+00h 1\n", + " 181 0.0000000e+00 2.24e-08 2.57e-04 -7.0 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 182 0.0000000e+00 2.24e-08 3.90e-11 -7.0 9.85e-08 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 182\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 3.8958489431350689e-11 3.8958489431350689e-11\n", + "Constraint violation....: 2.9103830456733704e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593320084580268e-14 2.8593320084580268e-14\n", + "Complementarity.........: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "Overall NLP error.......: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 253\n", + "Number of objective gradient evaluations = 22\n", + "Number of equality constraint evaluations = 253\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 185\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 182\n", + "Total seconds in IPOPT = 0.150\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Check physical units consistency, solve and check solver status\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.util.check_units import assert_units_consistent\n", + "\n", + "assert_units_consistent(m)\n", + "results = solver.solve(m, tee=True, symbolic_solver_labels=True)\n", + "assert results.solver.termination_condition == TerminationCondition.optimal" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For comparison, we will call and build the HDA flowsheet replacing the second `Flash` with a `TrayColumn` distillation unit model. The flowsheet costing occurs in the external script `hda_flowsheets_for_costing_notebook.py` and is not shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Solving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Adding distillation column and resolving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 17\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Complete.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n" + ] + } + ], + "source": [ + "from pyomo.common.log import LoggingIntercept\n", + "import logging\n", + "from io import StringIO\n", + "\n", + "stream = StringIO()\n", + "with LoggingIntercept(stream, \"idaes\", logging.WARNING):\n", + " # Source file for prebuilt flowsheets\n", + " from hda_flowsheets_for_costing_notebook import hda_with_distillation\n", + "\n", + " # Build hda model with distillation column and return model object\n", + " n = hda_with_distillation(tee=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Results Comparison and Visualization\n", + "For the two flowsheets above, let's sum the total operating and capital costs of each scenario. We will display overall process economics results and compare the two flowsheets:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Imports and data gathering\n", + "from matplotlib import pyplot as plt\n", + "\n", + "plt.style.use(\"dark_background\") # if using browser in dark mode, uncomment this line\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "# Automatically get units that we costed - this will exclude C101 for both flowsheets\n", + "\n", + "two_flash_unitlist = [\n", + " getattr(m.fs, unit) for unit in dir(m.fs) if hasattr(getattr(m.fs, unit), \"costing\")\n", + "]\n", + "distillation_unitlist = [\n", + " getattr(n.fs, unit) for unit in dir(n.fs) if hasattr(getattr(n.fs, unit), \"costing\")\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Equipmentfs.H101fs.R101fs.F101fs.F102fs.D101fs.H102
Distillation13.28333413.5522947.7813320.0000007.607433.32944
Two Flash13.28333410.7558787.7813327.7813320.000000.00000
\n", + "
" + ], + "text/plain": [ + "Equipment fs.H101 fs.R101 fs.F101 fs.F102 fs.D101 fs.H102\n", + "Distillation 13.283334 13.552294 7.781332 0.000000 7.60743 3.32944\n", + "Two Flash 13.283334 10.755878 7.781332 7.781332 0.00000 0.00000" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Compare equipment purchase costs (actual capital costs)\n", + "\n", + "two_flash_capcost = {\n", + " unit.name: value(unit.costing.capital_cost / 1e3) for unit in two_flash_unitlist\n", + "}\n", + "distillation_capcost = {\n", + " unit.name: value(unit.costing.capital_cost / 1e3) for unit in distillation_unitlist\n", + "}\n", + "\n", + "two_flash_capdf = pd.DataFrame(\n", + " list(two_flash_capcost.items()), columns=[\"Equipment\", \"Two Flash\"]\n", + ").set_index(\"Equipment\")\n", + "distillation_capdf = pd.DataFrame(\n", + " list(distillation_capcost.items()), columns=[\"Equipment\", \"Distillation\"]\n", + ").set_index(\"Equipment\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "capcosts = two_flash_capdf.add(distillation_capdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "# Sort according to an easier order to view\n", + "capcosts = capcosts[[\"fs.H101\", \"fs.R101\", \"fs.F101\", \"fs.F102\", \"fs.D101\", \"fs.H102\"]]\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(capcosts) # view dataframe before plotting\n", + "\n", + "capplot = capcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Total Capital Costs\", ylabel=\"$1000\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Utilitiescoolingheating
Distillation60.192008367.404722
Two Flash47.028803372.093536
\n", + "
" + ], + "text/plain": [ + "Utilities cooling heating\n", + "Distillation 60.192008 367.404722\n", + "Two Flash 47.028803 372.093536" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Compare operating costs (per year)\n", + "\n", + "two_flash_opcost = {\n", + " \"cooling\": value(3600 * 24 * 365 * m.fs.cooling_cost / 1e3),\n", + " \"heating\": value(3600 * 24 * 365 * m.fs.heating_cost / 1e3),\n", + "}\n", + "distillation_opcost = {\n", + " \"cooling\": value(3600 * 24 * 365 * n.fs.cooling_cost / 1e3),\n", + " \"heating\": value(3600 * 24 * 365 * n.fs.heating_cost / 1e3),\n", + "}\n", + "\n", + "two_flash_opdf = pd.DataFrame(\n", + " list(two_flash_opcost.items()), columns=[\"Utilities\", \"Two Flash\"]\n", + ").set_index(\"Utilities\")\n", + "distillation_opdf = pd.DataFrame(\n", + " list(distillation_opcost.items()), columns=[\"Utilities\", \"Distillation\"]\n", + ").set_index(\"Utilities\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "opcosts = two_flash_opdf.add(distillation_opdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(opcosts) # view dataframe before plotting\n", + "\n", + "opplot = opcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Operating Costs\", ylabel=\"$1000/year\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Costscapitaloperating
Distillation45.553829427.596731
Two Flash39.601876419.122339
\n", + "
" + ], + "text/plain": [ + "Costs capital operating\n", + "Distillation 45.553829 427.596731\n", + "Two Flash 39.601876 419.122339" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAHvCAYAAABQTQWGAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOyVJREFUeJzt3Qd40+X+//93W1pEaJlSoEyZhyUoyFAQBARBZCkOQIGjMhQXKoILxzmAylBQ4QgoIoKIAoIoKFPZQ7HsvUcBmWVD/tf7/v6TX1M6krY0zf15Pq4rVzPupHc+SZpX7xkiIi4BAACwWGigKwAAAHC9EXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AC4rj788EN57rnnsuzjOdnLL78sPXv2lKwiJCRERo4cKU2aNAl0VWChEFZaBnzXq1cvqVu3rjz66KPicl27SPmIESPkn3/+kTfffPOa+yi9z9mzZ+XYsWOybt06+eWXX+TIkSMp/s5PPvlE8uXLJ//5z3/MfVKjYaB27dqpltu1a5f07ds3xTIff/yxbN26VYYPHy5ptXHjRlPvBx98MMVy77zzjpQtW9Zz+fz587J9+3b57rvvZPPmzX4/Xnql9blHRkZK69atpUaNGpI7d26Ji4szz+OHH35I9bXOzLpWqVJF1qxZI3feeacsX75c2rVrJw888ECq97ty5Yp07NjR59fL3+Py1ltvSadOneRf//qXXLp0yefnA6SGFh7ADxpcHn74YQkNTfqj06pVq2v+O3Xf58cff5Tp06fLokWL5OTJk/Lvf/9b9u3bZ76kbrjhhiQfT4OL/geuX0RPP/20T3VcuXKlTJs2zXPauXOn+f1nzpzxun7+/PmpPlbLli09Ye160+OmJ3f9Vq1aZX5/bGysPP7445LZ0vLcNQjv3r1bevfuLYcPH5a5c+ean507d5a9e/ean1mlru+99578/vvvJuyoTZs2eb0/9H2q75u8efN6Xa/vYX9fL3+Oy7BhwyQmJkaeeOKJDDk2QEL6byonjgHvAR/eAxMnTnSpsLCwJG/fu3eva+nSpT7f54EHHnBdunTJNWXKlCQfb/To0eYxP/zwQ9eJEydcN954o9+vU9OmTc3v79atm9/33blzp6l/ej4fGzdudH333XepltPjps814XURERGurVu3uk6ePOnKnj27X4+X3pO/z71du3bmOA8bNizJ27t37+56/fXXs0Rdixcv7rp8+bLrscceS7ZMTEyMeT7Dhw9P1+uVluMyefJkV2xs7HV/jTmJo45BNq/oAyBTTZkyRe666y555plnpH79+ua/ardcuXLJQw89JO+//76MHz9enn/+eWnfvr18+eWXGfK7S5UqZbomSpcubVp/tMVHuxfcXXUTJ06Um266SerUqWPOJ+4Ge+ONN6RixYqebg7tlpg3b57MmDFDMsrFixfNYz711FNSvnx5+fvvv5Ms52tdPvvsM1m7dq2MHTvWtCBo94qWHT16tOkSckvtuScWHh4uH330kelue/HFF5Mso2NToqKi/HoN3F1B2sVTqVIlM8ZFu/O++uorUz4tdVX6vgoLC8vQ1yqp10uPR1qOi7aGapeldrtpixGQEejSAgJswoQJnu6wxN0A2bNnN1/G+gU2e/ZsefLJJzPkd+pYig0bNpiQtWzZMjPu6IsvvpDffvtNIiIiTBntptDxRvv370+yG+yPP/7wXD9nzhy5fPmyfP311/L5559LRtLgp86dO5dsGV/ros9bu34mTZok0dHRpjunQYMGpjumZMmSnnKpPffE9DhqN8w333wjV69eTbbcqVOn/HoN8ufPbwJaly5dTGhYvXq1lCtXzoy9cR8Xf+uq9Dlv2bJFjh8/Lhkt4euVluOili5dan42bNgww+sHZwt4MxMnjkGwvAfc3VOTJk0y5xOf4uPj/erS0lOePHnM7TNmzPC6fsWKFaZp3325RYsWplzFihXT1aWlv0+7HH755RdXSEiIp1y9evVMuf79+6e5q6R169bmMapWrZohXVrlypVznTp1yrVp0ya/Hy+puhw8eNB15swZV61atTzXRUVFuU6fPu0aMWKE1/39ee7PPfec+V36O30p7+tr0LlzZ3M5Ojra6/758+d3hYeHp/l10vKzZs1KsUxaurQSv17+Hhf3SY/JlStXXKNGjfLrfpw4BpLCMaBLC0gDHbiZ1H+saZlO6265uPHGGz3X3XLLLVKzZk155ZVXPNfNmjXLDEDWrpjkugd80aJFC9OFoINDE3ad6ADWFStWmJal/v37p/o42r2ig1S1S65gwYKSLVs2z3OoWrVqst1PKdHZaO5uGW3d0BlE+py1Cyaj6qJdQu6Buu7WBX3e1apVk7TKmTNnqq1Q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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Compare total costs (capital costs and operating costs)\n", + "\n", + "two_flash_totcost = {\n", + " \"capital\": sum(two_flash_capcost[idx] for idx in two_flash_capcost),\n", + " \"operating\": value(m.fs.operating_cost) / 1e3,\n", + "}\n", + "distillation_totcost = {\n", + " \"capital\": sum(distillation_capcost[idx] for idx in distillation_capcost),\n", + " \"operating\": value(n.fs.operating_cost) / 1e3,\n", + "}\n", + "\n", + "two_flash_totdf = pd.DataFrame(\n", + " list(two_flash_totcost.items()), columns=[\"Costs\", \"Two Flash\"]\n", + ").set_index(\"Costs\")\n", + "distillation_totdf = pd.DataFrame(\n", + " list(distillation_totcost.items()), columns=[\"Costs\", \"Distillation\"]\n", + ").set_index(\"Costs\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "totcosts = two_flash_totdf.add(distillation_totdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(totcosts) # view dataframe before plotting\n", + "\n", + "totplot = totcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Total Plant Cost (TPC)\", ylabel=\"$1000/year\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's compare the total costs on a production basis. This will account for the greater efficiency provided by the distillation column relative to the less-expensive second flash unit:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Two flash case over one year: $459K / 4477 kmol benzene = $102.45 per kmol benzene produced\n", + "Distillation case over one year: $473K / 5108 kmol benzene = $92.63 per kmol benzene produced\n" + ] + } + ], + "source": [ + "two_flash_cost = value(1e3 * sum(two_flash_totcost[idx] for idx in two_flash_totcost))\n", + "two_flash_prod = value(\n", + " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] * 365 * 24 * 3600\n", + ")\n", + "distillation_cost = value(\n", + " 1e3 * sum(distillation_totcost[idx] for idx in distillation_totcost)\n", + ")\n", + "distillation_prod = value(n.fs.D101.condenser.distillate.flow_mol[0] * 365 * 24 * 3600)\n", + "\n", + "print(\n", + " f\"Two flash case over one year: ${two_flash_cost/1e3:0.0f}K / {two_flash_prod/1e3:0.0f} kmol benzene = ${two_flash_cost/(two_flash_prod/1e3):0.2f} per kmol benzene produced\"\n", + ")\n", + "print(\n", + " f\"Distillation case over one year: ${distillation_cost/1e3:0.0f}K / {distillation_prod/1e3:0.0f} kmol benzene = ${distillation_cost/(distillation_prod/1e3):0.2f} per kmol benzene produced\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Summary\n", + "In this example, IDAES Process Costing Framework methods were applied to two HDA flowsheets for capital cost estimation. The costing blocks calls showcased multiple methods to define unit costing, demonstrating the flexibility and best practice of the costing framework. In the basic examples, the two-flash HDA did not include costing and the distillation HDA estimated a reactor capital cost comprising 3.3% of the total plant cost (TPC). With more rigorous costing, IDAES obtained total capital costs of 8.5% TPC (two flash HDA) and 9.6% (distillation HDA) and better modeled the impact of equipment cost on process economics. As printed above, the IDAES Process Costing Framework confirmed that replacing the second flash drum with a distillation column results in increased equipment costs, increased production and decreased cost per unit product." + ] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" + } }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "# HDA Flowsheet Costing\n", - "Maintainer: Brandon Paul \n", - "Author: Brandon Paul \n", - "Updated: 2023-06-01 \n", - "\n", - "\n", - "## Note\n", - "\n", - "This example will demonstrate adding capital and operating costs to the two HDA examples, the basic [HDA with Flash](../tut/hda_flowsheet_solution_test.ipynb) and a comparison with the HDA with Distillation.\n", - "\n", - "\n", - "## Learning outcomes\n", - "\n", - "- Import external pre-built steady-state flowsheets using the IDAES unit model library\n", - "- Define and add costing blocks using the IDAES Process Costing Framework\n", - "- Formulate and solve a process economics optimization problem\n", - " - Defining an objective function\n", - " - Setting variable bounds\n", - " - Adding additional constraints \n", - "\n", - "\n", - "## Problem Statement\n", - "\n", - "Hydrodealkylation is a chemical reaction that often involves reacting\n", - "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", - "simpler aromatic hydrocarbon devoid of functional groups. In this\n", - "example, toluene will be reacted with hydrogen gas at high temperatures\n", - " to form benzene via the following reaction:\n", - "\n", - "**C6H5CH3 + H2 → C6H6 + CH4**\n", - "\n", - "\n", - "This reaction is often accompanied by an equilibrium side reaction\n", - "which forms diphenyl, which we will neglect for this example.\n", - "\n", - "This example is based on the 1967 AIChE Student Contest problem as\n", - "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", - "McGraw-Hill.\n", - "\n", - "Users may refer to the prior examples linked at the top of this notebook for detailed process descriptions of the two HDA configurations. As before, the properties required for this module are defined in\n", - "\n", - "- `hda_ideal_VLE.py`\n", - "- `idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE`\n", - "- `hda_reaction.py`\n", - "\n", - "Additionally, we will be importing externally-defined flowsheets for the two HDA configurations from\n", - "\n", - "- `hda_flowsheets_for_costing_notebook.py`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Import and run HDA Flowsheets\n", - "First, we will generate solved flowsheets for each HDA model. The external scripts build and set inputs for the flowsheets, initialize unit models and streams, and solve the flowsheets before returning the model objects. Note that the HDA flowsheets contain all unit models and stream connections, and no costing equations." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The flowsheet utilizes the Wegstein method to iteratively solve circular dependencies such as recycle streams, and is intended to approach a feasible solution. As such, the calls below will fail to converge after 3 iterations and pass to IPOPT to obtain an optimal solution as expected:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Source file for prebuilt flowsheets\n", - "from hda_flowsheets_for_costing_notebook import hda_with_flash\n", - "\n", - "# Build hda model with second flash unit and return model object\n", - "m = hda_with_flash(tee=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## IDAES Process Costing Framework\n", - "IDAES provides a library of capital costing correlations based on those in the following source:\n", - "\n", - "*Process and Product Design Principles: Synthesis, Analysis, and Evaluation*. Seider, Seader, Lewin, Windagdo, 3rd Ed. John Wiley and Sons Chapter 22. Cost Accounting and Capital Cost Estimation 22.2 Cost Indexes and Capital Investment.\n", - "\n", - "Currently, IDAES supports calculation of capital costing for a wide array of unit operations, vesseel sizing and material properties, and specific unit options such as column tray types and heat exchanger configurations. Users may find further information on specific costing methods and options in the IDAES Process Costing Framework documentation (link pending).\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add Operating Cost Equations\n", - "Before adding capital costing blocks, we will add operating cost equations taken from the basic [HDA with Flash](../tut/hda_flowsheet_solution_test.ipynb) and the HDA with Distillation examples. The examples assume constant cooling and heating coefficients over an annual cost basis. The IDAES Generic Costing Framework does not currently support variable cost calculations." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Required imports\n", - "from pyomo.environ import Expression\n", - "\n", - "# Operating costs for HDA with second flash (model m)\n", - "m.fs.cooling_cost = Expression(\n", - " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", - ")\n", - "m.fs.heating_cost = Expression(\n", - " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", - ")\n", - "m.fs.operating_cost = Expression(\n", - " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add Capital Costing\n", - "Below, we will add add capital costing blocks to the imported flowsheets and evaluate the economic impact of replacing the second Flash with a Distillation column. First, let's import and define the main flowsheet costing block:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Import costing methods - classes, heaters, vessels, compressors, columns\n", - "from idaes.models.costing.SSLW import (\n", - " SSLWCosting,\n", - " SSLWCostingData,\n", - ")\n", - "from idaes.core import UnitModelCostingBlock\n", - "\n", - "# Costing block\n", - "m.fs.costing = SSLWCosting()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will build the relevant costing blocks for the equipment we wish to cost. Note how the costing block, methods and flags are passed as arguments in the costing block call itself. Each unit model will have a single costing block, but each flowsheet model (m and n) will also have a single costing block for flowsheet-level properties.\n", - "\n", - "Users should note that IDAES costing methods support a wide array of heating sources (e.g. fired, steam boiler, hot water) and do not support direct capital costing of coolers. If users wish to cost Heater units acting as coolers, it is necessary to cost a \"dummy\" [0D shell and tube exchanger](https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/heat_exchanger.html) with appropriate aliased hot stream properties and proper cooling water properties. This is not demonstrated here, as the HDA examples take advantage of Flash and Condenser operations to recover liquid product.\n", - "\n", - "Capital costing is independent of unit model connections, and building cost equations may be done piecewise in this fashion. Default options are passed explicitly to demonstrate proper syntax and usage. Now that all required properties are defined, let's cost our models connecting costing blocks, methods and unit models in each flowsheet." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Flexibility of Costing Block Definitions\n", - "IDAES supports many ways to define batches of costing blocks, and several are shown in the example. Users may employ whichever method fits their modeling needs for explicit or concise code. In the code below, note how the unit model itself is never passed to the costing method; when the full model is executed, the costing block will automatically connect its parent block with child equation blocks.\n", - "\n", - "`Compressor` unit models with isothermal or adiabatic thermodynamics are too simple to cost and are therefore excluded from the economic analysis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's define costing for the heater unit:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.costing.SSLW import (\n", - " HeaterMaterial,\n", - " HeaterSource,\n", - ")\n", - "\n", - "# Costing for heater - m.fs.H101\n", - "m.fs.H101.costing = UnitModelCostingBlock(\n", - " flowsheet_costing_block=m.fs.costing,\n", - " costing_method=SSLWCostingData.cost_fired_heater,\n", - " costing_method_arguments={\n", - " \"material_type\": HeaterMaterial.CarbonSteel,\n", - " \"heat_source\": HeaterSource.Fuel,\n", - " },\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The costing module provides a `unit_mapping` dictionary linking generic unit model classes with recommended costing methods. In this example, StoichiometricReactor and Flash vessels utilize different vessel costing methods with similar arguments. The diameter and length attributes need to exist in order to cost vessel sizing and material requirements, and we add them if they don't exist already. The `unit_mapping` method provides an opportunity to automatically select the correct vessel orientation (vertical or horizontal) based on the unit type; passing a `StoichiometricReactor` or `PFR` class object will call the `cost_horizontal_vessel` method, while passing a `Flash` or `CSTR` class object will call the `cost_vertical_vessel` method.\n", - "\n", - "All vessels are assigned costing succinctly via a loop below - users may define each block individually if desired:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.costing.SSLW import (\n", - " VesselMaterial,\n", - " TrayType,\n", - " TrayMaterial,\n", - ")\n", - "\n", - "from idaes.core.util.constants import Constants\n", - "from pyomo.environ import Var, Constraint, units as pyunits, Param, value\n", - "from idaes.models.unit_models import StoichiometricReactor, Flash\n", - "\n", - "# Map unit models to unit classes\n", - "# Will pass to unit_mapping which calls costing methods based on unit class\n", - "unit_class_mapping = {\n", - " m.fs.R101: StoichiometricReactor,\n", - " m.fs.F101: Flash,\n", - " m.fs.F102: Flash,\n", - "}\n", - "\n", - "# Costing for vessels - m.fs.R101, m.fs.F101, m.fs.F102\n", - "\n", - "# Loop over units\n", - "for unit in [m.fs.R101, m.fs.F101, m.fs.F102]:\n", - " # Get correct unit class for unit model\n", - " unit_class = unit_class_mapping[unit]\n", - "\n", - " # Add dimension variables and constraint if they don't exist\n", - " if not hasattr(unit, \"diameter\"):\n", - " unit.diameter = Var(initialize=1, units=pyunits.m)\n", - " if not hasattr(unit, \"length\"):\n", - " unit.length = Var(initialize=1, units=pyunits.m)\n", - " if hasattr(unit, \"volume\"): # if volume exists, set diameter from volume\n", - " unit.volume_eq = Constraint(\n", - " expr=unit.volume[0] == unit.length * unit.diameter**2 * 0.25 * Constants.pi\n", - " )\n", - " else: # fix diameter directly\n", - " unit.diameter.fix(0.2214 * pyunits.m)\n", - " # Either way, fix L/D to calculate L from D\n", - " unit.L_over_D = Constraint(expr=unit.length == 3 * unit.diameter)\n", - "\n", - " # Define vessel costing\n", - " unit.costing = UnitModelCostingBlock(\n", - " flowsheet_costing_block=unit.parent_block().costing, # e.g. m.fs.R101.costing\n", - " costing_method=SSLWCostingData.unit_mapping[\n", - " unit_class\n", - " ], # e.g. cost_vertical_vessel()\n", - " costing_method_arguments={\n", - " \"material_type\": VesselMaterial.CarbonSteel,\n", - " \"shell_thickness\": 1.25 * pyunits.inch,\n", - " },\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Solve Flowsheet Costing Blocks\n", - "Now, we may solve the full flowsheet for all costing blocks:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Eefine solver\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", - "\n", - "# Check that the degrees of freedom is zero\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "\n", - "assert degrees_of_freedom(m) == 0" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Check physical units consistency, solve and check solver status\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.util.check_units import assert_units_consistent\n", - "\n", - "assert_units_consistent(m)\n", - "results = solver.solve(m, tee=True, symbolic_solver_labels=True)\n", - "assert results.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For comparison, we will call and build the HDA flowsheet replacing the second `Flash` with a `TrayColumn` distillation unit model. The flowsheet costing occurs in the external script `hda_flowsheets_for_costing_notebook.py` and is not shown here:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "from pyomo.common.log import LoggingIntercept\n", - "import logging\n", - "from io import StringIO\n", - "\n", - "stream = StringIO()\n", - "with LoggingIntercept(stream, \"idaes\", logging.WARNING):\n", - " # Source file for prebuilt flowsheets\n", - " from hda_flowsheets_for_costing_notebook import hda_with_distillation\n", - "\n", - " # Build hda model with distillation column and return model object\n", - " n = hda_with_distillation(tee=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results Comparison and Visualization\n", - "For the two flowsheets above, let's sum the total operating and capital costs of each scenario. We will display overall process economics results and compare the two flowsheets:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports and data gathering\n", - "from matplotlib import pyplot as plt\n", - "\n", - "plt.style.use(\"dark_background\") # if using browser in dark mode, uncomment this line\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "# Automatically get units that we costed - this will exclude C101 for both flowsheets\n", - "\n", - "two_flash_unitlist = [\n", - " getattr(m.fs, unit) for unit in dir(m.fs) if hasattr(getattr(m.fs, unit), \"costing\")\n", - "]\n", - "distillation_unitlist = [\n", - " getattr(n.fs, unit) for unit in dir(n.fs) if hasattr(getattr(n.fs, unit), \"costing\")\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Compare equipment purchase costs (actual capital costs)\n", - "\n", - "two_flash_capcost = {\n", - " unit.name: value(unit.costing.capital_cost / 1e3) for unit in two_flash_unitlist\n", - "}\n", - "distillation_capcost = {\n", - " unit.name: value(unit.costing.capital_cost / 1e3) for unit in distillation_unitlist\n", - "}\n", - "\n", - "two_flash_capdf = pd.DataFrame(\n", - " list(two_flash_capcost.items()), columns=[\"Equipment\", \"Two Flash\"]\n", - ").set_index(\"Equipment\")\n", - "distillation_capdf = pd.DataFrame(\n", - " list(distillation_capcost.items()), columns=[\"Equipment\", \"Distillation\"]\n", - ").set_index(\"Equipment\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "capcosts = two_flash_capdf.add(distillation_capdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "# Sort according to an easier order to view\n", - "capcosts = capcosts[[\"fs.H101\", \"fs.R101\", \"fs.F101\", \"fs.F102\", \"fs.D101\", \"fs.H102\"]]\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(capcosts) # view dataframe before plotting\n", - "\n", - "capplot = capcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Total Capital Costs\", ylabel=\"$1000\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Compare operating costs (per year)\n", - "\n", - "two_flash_opcost = {\n", - " \"cooling\": value(3600 * 24 * 365 * m.fs.cooling_cost / 1e3),\n", - " \"heating\": value(3600 * 24 * 365 * m.fs.heating_cost / 1e3),\n", - "}\n", - "distillation_opcost = {\n", - " \"cooling\": value(3600 * 24 * 365 * n.fs.cooling_cost / 1e3),\n", - " \"heating\": value(3600 * 24 * 365 * n.fs.heating_cost / 1e3),\n", - "}\n", - "\n", - "two_flash_opdf = pd.DataFrame(\n", - " list(two_flash_opcost.items()), columns=[\"Utilities\", \"Two Flash\"]\n", - ").set_index(\"Utilities\")\n", - "distillation_opdf = pd.DataFrame(\n", - " list(distillation_opcost.items()), columns=[\"Utilities\", \"Distillation\"]\n", - ").set_index(\"Utilities\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "opcosts = two_flash_opdf.add(distillation_opdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(opcosts) # view dataframe before plotting\n", - "\n", - "opplot = opcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Operating Costs\", ylabel=\"$1000/year\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Compare total costs (capital costs and operating costs)\n", - "\n", - "two_flash_totcost = {\n", - " \"capital\": sum(two_flash_capcost[idx] for idx in two_flash_capcost),\n", - " \"operating\": value(m.fs.operating_cost) / 1e3,\n", - "}\n", - "distillation_totcost = {\n", - " \"capital\": sum(distillation_capcost[idx] for idx in distillation_capcost),\n", - " \"operating\": value(n.fs.operating_cost) / 1e3,\n", - "}\n", - "\n", - "two_flash_totdf = pd.DataFrame(\n", - " list(two_flash_totcost.items()), columns=[\"Costs\", \"Two Flash\"]\n", - ").set_index(\"Costs\")\n", - "distillation_totdf = pd.DataFrame(\n", - " list(distillation_totcost.items()), columns=[\"Costs\", \"Distillation\"]\n", - ").set_index(\"Costs\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "totcosts = two_flash_totdf.add(distillation_totdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(totcosts) # view dataframe before plotting\n", - "\n", - "totplot = totcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Total Plant Cost (TPC)\", ylabel=\"$1000/year\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's compare the total costs on a production basis. This will account for the greater efficiency provided by the distillation column relative to the less-expensive second flash unit:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "two_flash_cost = value(1e3 * sum(two_flash_totcost[idx] for idx in two_flash_totcost))\n", - "two_flash_prod = value(\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] * 365 * 24 * 3600\n", - ")\n", - "distillation_cost = value(\n", - " 1e3 * sum(distillation_totcost[idx] for idx in distillation_totcost)\n", - ")\n", - "distillation_prod = value(n.fs.D101.condenser.distillate.flow_mol[0] * 365 * 24 * 3600)\n", - "\n", - "print(\n", - " f\"Two flash case over one year: ${two_flash_cost/1e3:0.0f}K / {two_flash_prod/1e3:0.0f} kmol benzene = ${two_flash_cost/(two_flash_prod/1e3):0.2f} per kmol benzene produced\"\n", - ")\n", - "print(\n", - " f\"Distillation case over one year: ${distillation_cost/1e3:0.0f}K / {distillation_prod/1e3:0.0f} kmol benzene = ${distillation_cost/(distillation_prod/1e3):0.2f} per kmol benzene produced\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Summary\n", - "In this example, IDAES Process Costing Framework methods were applied to two HDA flowsheets for capital cost estimation. The costing blocks calls showcased multiple methods to define unit costing, demonstrating the flexibility and best practice of the costing framework. In the basic examples, the two-flash HDA did not include costing and the distillation HDA estimated a reactor capital cost comprising 3.3% of the total plant cost (TPC). With more rigorous costing, IDAES obtained total capital costs of 8.5% TPC (two flash HDA) and 9.6% (distillation HDA) and better modeled the impact of equipment cost on process economics. As printed above, the IDAES Process Costing Framework confirmed that replacing the second flash drum with a distillation column results in increased equipment costs, increased production and decreased cost per unit product." - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.12" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_usr.ipynb b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_usr.ipynb index ffcb1398..247da75e 100644 --- a/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_usr.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/hda_flowsheet_with_costing_usr.ipynb @@ -1,562 +1,2381 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [ + "header", + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# HDA Flowsheet Costing\n", + "Maintainer: Brandon Paul \n", + "Author: Brandon Paul \n", + "Updated: 2023-06-01 \n", + "\n", + "\n", + "## Note\n", + "\n", + "This example will demonstrate adding capital and operating costs to the two HDA examples, the basic [HDA with Flash](../tut/hda_flowsheet_solution_usr.ipynb) and a comparison with the HDA with Distillation.\n", + "\n", + "\n", + "## Learning outcomes\n", + "\n", + "- Import external pre-built steady-state flowsheets using the IDAES unit model library\n", + "- Define and add costing blocks using the IDAES Process Costing Framework\n", + "- Formulate and solve a process economics optimization problem\n", + " - Defining an objective function\n", + " - Setting variable bounds\n", + " - Adding additional constraints \n", + "\n", + "\n", + "## Problem Statement\n", + "\n", + "Hydrodealkylation is a chemical reaction that often involves reacting\n", + "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", + "simpler aromatic hydrocarbon devoid of functional groups. In this\n", + "example, toluene will be reacted with hydrogen gas at high temperatures\n", + " to form benzene via the following reaction:\n", + "\n", + "**C6H5CH3 + H2 \u2192 C6H6 + CH4**\n", + "\n", + "\n", + "This reaction is often accompanied by an equilibrium side reaction\n", + "which forms diphenyl, which we will neglect for this example.\n", + "\n", + "This example is based on the 1967 AIChE Student Contest problem as\n", + "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", + "McGraw-Hill.\n", + "\n", + "Users may refer to the prior examples linked at the top of this notebook for detailed process descriptions of the two HDA configurations. As before, the properties required for this module are defined in\n", + "\n", + "- `hda_ideal_VLE.py`\n", + "- `idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE`\n", + "- `hda_reaction.py`\n", + "\n", + "Additionally, we will be importing externally-defined flowsheets for the two HDA configurations from\n", + "\n", + "- `hda_flowsheets_for_costing_notebook.py`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import and run HDA Flowsheets\n", + "First, we will generate solved flowsheets for each HDA model. The external scripts build and set inputs for the flowsheets, initialize unit models and streams, and solve the flowsheets before returning the model objects. Note that the HDA flowsheets contain all unit models and stream connections, and no costing equations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The flowsheet utilizes the Wegstein method to iteratively solve circular dependencies such as recycle streams, and is intended to approach a feasible solution. As such, the calls below will fail to converge after 3 iterations and pass to IPOPT to obtain an optimal solution as expected:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "fs.s03\n", + "fs.H101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n", + "2026-07-22 11:48:38 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:39 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:40 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:41 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.847064471825717e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.84708910810722e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:42 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.791876189065646e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.791876189071645e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:43 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:44 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552214517320668e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552214903270587e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:45 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:46 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718391018306772e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718391017993457e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:47 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:48 [INFO] idaes.init.fs.F102.control_volume.properties_out: Initialization Complete\n", + "Solving flowsheet...\n", + "\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=5000\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1031\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 934\n", + "\n", + "Total number of variables............................: 340\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 146\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 340\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.60e+04 0.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 8.69e+03 1.42e+03 -1.0 2.00e+04 - 9.71e-01 4.67e-01H 1\n", + " 2 0.0000000e+00 3.05e+03 1.56e+03 -1.0 1.60e+04 - 9.79e-01 4.90e-01h 1\n", + " 3 0.0000000e+00 1.58e+03 1.55e+05 -1.0 1.40e+04 - 9.90e-01 4.99e-01h 1\n", + " 4 0.0000000e+00 5.49e+02 8.87e+08 -1.0 8.42e+03 - 1.00e+00 9.57e-01h 1\n", + " 5 0.0000000e+00 4.25e+03 2.87e+10 -1.0 8.02e+02 - 1.00e+00 9.90e-01h 1\n", + " 6 0.0000000e+00 2.25e+03 1.51e+10 -1.0 8.39e+00 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 2.27e+01 1.40e+08 -1.0 2.45e-03 - 1.00e+00 1.00e+00f 1\n", + " 8 0.0000000e+00 2.45e-03 1.23e+04 -1.0 2.39e-05 - 1.00e+00 1.00e+00h 1\n", + " 9 0.0000000e+00 2.24e-08 4.65e-01 -2.5 9.06e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 0.0000000e+00 2.24e-08 1.41e+05 -5.7 1.38e-07 - 1.00e+00 5.00e-01h 2\n", + " 11 0.0000000e+00 7.45e-09 5.56e-03 -5.7 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 12 0.0000000e+00 7.45e-09 2.47e-09 -5.7 9.00e-08 - 1.00e+00 1.00e+00h 1\n", + " 13 0.0000000e+00 2.24e-08 5.06e-07 -7.0 1.38e-07 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 13\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "Constraint violation....: 5.8207660913467407e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593319938534624e-14 2.8593319938534624e-14\n", + "Complementarity.........: 9.0909090909115134e-08 9.0909090909115134e-08\n", + "Overall NLP error.......: 5.0570048536224512e-07 5.0570048536224512e-07\n", + "\n", + "\n", + "Number of objective function evaluations = 17\n", + "Number of objective gradient evaluations = 14\n", + "Number of equality constraint evaluations = 17\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 14\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 13\n", + "Total seconds in IPOPT = 0.018\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Complete.\n", + "\n" + ] + } + ], + "source": [ + "# Source file for prebuilt flowsheets\n", + "from hda_flowsheets_for_costing_notebook import hda_with_flash\n", + "\n", + "# Build hda model with second flash unit and return model object\n", + "m = hda_with_flash(tee=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## IDAES Process Costing Framework\n", + "IDAES provides a library of capital costing correlations based on those in the following source:\n", + "\n", + "*Process and Product Design Principles: Synthesis, Analysis, and Evaluation*. Seider, Seader, Lewin, Windagdo, 3rd Ed. John Wiley and Sons Chapter 22. Cost Accounting and Capital Cost Estimation 22.2 Cost Indexes and Capital Investment.\n", + "\n", + "Currently, IDAES supports calculation of capital costing for a wide array of unit operations, vesseel sizing and material properties, and specific unit options such as column tray types and heat exchanger configurations. Users may find further information on specific costing methods and options in the IDAES Process Costing Framework documentation (link pending).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Operating Cost Equations\n", + "Before adding capital costing blocks, we will add operating cost equations taken from the basic [HDA with Flash](../tut/hda_flowsheet_solution_usr.ipynb) and the HDA with Distillation examples. The examples assume constant cooling and heating coefficients over an annual cost basis. The IDAES Generic Costing Framework does not currently support variable cost calculations." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Required imports\n", + "from pyomo.environ import Expression\n", + "\n", + "# Operating costs for HDA with second flash (model m)\n", + "m.fs.cooling_cost = Expression(\n", + " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", + ")\n", + "m.fs.heating_cost = Expression(\n", + " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", + ")\n", + "m.fs.operating_cost = Expression(\n", + " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add Capital Costing\n", + "Below, we will add add capital costing blocks to the imported flowsheets and evaluate the economic impact of replacing the second Flash with a Distillation column. First, let's import and define the main flowsheet costing block:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Import costing methods - classes, heaters, vessels, compressors, columns\n", + "from idaes.models.costing.SSLW import (\n", + " SSLWCosting,\n", + " SSLWCostingData,\n", + ")\n", + "from idaes.core import UnitModelCostingBlock\n", + "\n", + "# Costing block\n", + "m.fs.costing = SSLWCosting()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will build the relevant costing blocks for the equipment we wish to cost. Note how the costing block, methods and flags are passed as arguments in the costing block call itself. Each unit model will have a single costing block, but each flowsheet model (m and n) will also have a single costing block for flowsheet-level properties.\n", + "\n", + "Users should note that IDAES costing methods support a wide array of heating sources (e.g. fired, steam boiler, hot water) and do not support direct capital costing of coolers. If users wish to cost Heater units acting as coolers, it is necessary to cost a \"dummy\" [0D shell and tube exchanger](https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/heat_exchanger.html) with appropriate aliased hot stream properties and proper cooling water properties. This is not demonstrated here, as the HDA examples take advantage of Flash and Condenser operations to recover liquid product.\n", + "\n", + "Capital costing is independent of unit model connections, and building cost equations may be done piecewise in this fashion. Default options are passed explicitly to demonstrate proper syntax and usage. Now that all required properties are defined, let's cost our models connecting costing blocks, methods and unit models in each flowsheet." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Flexibility of Costing Block Definitions\n", + "IDAES supports many ways to define batches of costing blocks, and several are shown in the example. Users may employ whichever method fits their modeling needs for explicit or concise code. In the code below, note how the unit model itself is never passed to the costing method; when the full model is executed, the costing block will automatically connect its parent block with child equation blocks.\n", + "\n", + "`Compressor` unit models with isothermal or adiabatic thermodynamics are too simple to cost and are therefore excluded from the economic analysis." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define costing for the heater unit:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from idaes.models.costing.SSLW import (\n", + " HeaterMaterial,\n", + " HeaterSource,\n", + ")\n", + "\n", + "# Costing for heater - m.fs.H101\n", + "m.fs.H101.costing = UnitModelCostingBlock(\n", + " flowsheet_costing_block=m.fs.costing,\n", + " costing_method=SSLWCostingData.cost_fired_heater,\n", + " costing_method_arguments={\n", + " \"material_type\": HeaterMaterial.CarbonSteel,\n", + " \"heat_source\": HeaterSource.Fuel,\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The costing module provides a `unit_mapping` dictionary linking generic unit model classes with recommended costing methods. In this example, StoichiometricReactor and Flash vessels utilize different vessel costing methods with similar arguments. The diameter and length attributes need to exist in order to cost vessel sizing and material requirements, and we add them if they don't exist already. The `unit_mapping` method provides an opportunity to automatically select the correct vessel orientation (vertical or horizontal) based on the unit type; passing a `StoichiometricReactor` or `PFR` class object will call the `cost_horizontal_vessel` method, while passing a `Flash` or `CSTR` class object will call the `cost_vertical_vessel` method.\n", + "\n", + "All vessels are assigned costing succinctly via a loop below - users may define each block individually if desired:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from idaes.models.costing.SSLW import (\n", + " VesselMaterial,\n", + " TrayType,\n", + " TrayMaterial,\n", + ")\n", + "\n", + "from idaes.core.util.constants import Constants\n", + "from pyomo.environ import Var, Constraint, units as pyunits, Param, value\n", + "from idaes.models.unit_models import StoichiometricReactor, Flash\n", + "\n", + "# Map unit models to unit classes\n", + "# Will pass to unit_mapping which calls costing methods based on unit class\n", + "unit_class_mapping = {\n", + " m.fs.R101: StoichiometricReactor,\n", + " m.fs.F101: Flash,\n", + " m.fs.F102: Flash,\n", + "}\n", + "\n", + "# Costing for vessels - m.fs.R101, m.fs.F101, m.fs.F102\n", + "\n", + "# Loop over units\n", + "for unit in [m.fs.R101, m.fs.F101, m.fs.F102]:\n", + " # Get correct unit class for unit model\n", + " unit_class = unit_class_mapping[unit]\n", + "\n", + " # Add dimension variables and constraint if they don't exist\n", + " if not hasattr(unit, \"diameter\"):\n", + " unit.diameter = Var(initialize=1, units=pyunits.m)\n", + " if not hasattr(unit, \"length\"):\n", + " unit.length = Var(initialize=1, units=pyunits.m)\n", + " if hasattr(unit, \"volume\"): # if volume exists, set diameter from volume\n", + " unit.volume_eq = Constraint(\n", + " expr=unit.volume[0] == unit.length * unit.diameter**2 * 0.25 * Constants.pi\n", + " )\n", + " else: # fix diameter directly\n", + " unit.diameter.fix(0.2214 * pyunits.m)\n", + " # Either way, fix L/D to calculate L from D\n", + " unit.L_over_D = Constraint(expr=unit.length == 3 * unit.diameter)\n", + "\n", + " # Define vessel costing\n", + " unit.costing = UnitModelCostingBlock(\n", + " flowsheet_costing_block=unit.parent_block().costing, # e.g. m.fs.R101.costing\n", + " costing_method=SSLWCostingData.unit_mapping[\n", + " unit_class\n", + " ], # e.g. cost_vertical_vessel()\n", + " costing_method_arguments={\n", + " \"material_type\": VesselMaterial.CarbonSteel,\n", + " \"shell_thickness\": 1.25 * pyunits.inch,\n", + " },\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solve Flowsheet Costing Blocks\n", + "Now, we may solve the full flowsheet for all costing blocks:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Define solver\n", + "from idaes.core.solvers import get_solver\n", + "\n", + "solver = get_solver(\"ipopt_v2\", options={\"max_iter\": 500})\n", + "\n", + "# Check that the degrees of freedom is zero\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "\n", + "assert degrees_of_freedom(m) == 0" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.14.20: linear_solver=\"ma57\"\n", + "max_iter=500\n", + "nlp_scaling_method=\"gradient-based\"\n", + "tol=1e-06\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 604\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 569\n", + "\n", + "Total number of variables............................: 160\n", + " variables with only lower bounds: 10\n", + " variables with lower and upper bounds: 38\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 160\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.00e+05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (6534)\n", + " 1 0.0000000e+00 8.81e+04 5.45e+03 -1.0 9.27e+04 - 2.62e-01 1.20e-01h 1\n", + " 2 0.0000000e+00 6.34e+04 2.46e+03 -1.0 8.16e+04 - 9.83e-01 2.87e-01h 1\n", + " 3 0.0000000e+00 3.40e+04 1.76e+03 -1.0 5.81e+04 - 4.59e-01 4.86e-01h 1\n", + " 4 0.0000000e+00 2.33e+04 9.17e+04 -1.0 2.99e+04 - 7.04e-01 5.09e-01h 1\n", + " 5 0.0000000e+00 1.13e+04 7.52e+08 -1.0 1.47e+04 - 8.02e-01 9.65e-01h 1\n", + "Reallocating memory for MA57: lfact (7452)\n", + " 6 0.0000000e+00 5.50e+03 3.83e+08 -1.0 8.18e+02 - 9.90e-01 6.10e-01h 1\n", + " 7 0.0000000e+00 5.23e+03 3.45e+08 -1.0 3.84e+02 - 1.00e+00 5.07e-02h 1\n", + "Reallocating memory for MA57: lfact (8076)\n", + " 8 0.0000000e+00 5.22e+03 7.30e+08 -1.0 3.70e+02 - 1.00e+00 5.85e-04h 1\n", + " 9r 0.0000000e+00 5.22e+03 1.00e+03 2.3 0.00e+00 - 0.00e+00 3.66e-07R 5\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10r 0.0000000e+00 6.37e+04 2.29e+04 2.3 2.43e+07 - 1.50e-03 9.91e-04f 1\n", + " 11r 0.0000000e+00 1.51e+04 1.09e+05 2.3 2.98e+07 - 1.34e-01 2.58e-03f 1\n", + " 12r 0.0000000e+00 3.92e+04 1.08e+05 2.3 8.59e+07 - 8.37e-03 1.46e-02f 1\n", + " 13r 0.0000000e+00 1.67e+05 1.08e+05 2.3 5.23e+06 - 5.83e-03 9.06e-02f 1\n", + " 14r 0.0000000e+00 4.67e+05 1.05e+05 2.3 1.18e+07 - 2.42e-02 9.08e-02f 1\n", + " 15r 0.0000000e+00 4.64e+05 1.05e+05 2.3 5.75e+06 - 1.97e-03 6.57e-03h 1\n", + " 16r 0.0000000e+00 4.63e+05 9.23e+04 2.3 1.50e+04 -4.0 1.25e-01 1.34e-03h 1\n", + " 17r 0.0000000e+00 6.08e+05 8.46e+04 2.3 5.32e+06 - 8.37e-02 3.04e-01f 1\n", + " 18r 0.0000000e+00 5.71e+05 5.77e+04 2.3 1.87e+06 - 3.20e-01 1.38e-01f 1\n", + " 19r 0.0000000e+00 4.10e+05 5.27e+04 2.3 4.12e+06 - 9.00e-02 3.37e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r 0.0000000e+00 3.86e+05 4.93e+04 2.3 1.63e+04 -3.6 6.50e-02 5.85e-02f 1\n", + " 21r 0.0000000e+00 3.60e+05 4.51e+04 2.3 7.48e+03 -3.1 8.38e-02 6.63e-02h 1\n", + " 22r 0.0000000e+00 3.64e+05 4.08e+04 2.3 4.06e+06 - 9.58e-02 7.04e-02f 1\n", + " 23r 0.0000000e+00 3.86e+05 1.88e+05 2.3 5.59e+06 - 1.68e-01 1.49e-01f 1\n", + " 24r 0.0000000e+00 3.86e+05 1.88e+05 2.3 1.12e+02 4.7 1.81e-03 1.57e-03h 1\n", + " 25r 0.0000000e+00 3.86e+05 1.91e+05 2.3 1.55e+02 4.2 2.71e-03 1.11e-03h 1\n", + " 26r 0.0000000e+00 3.85e+05 1.86e+05 2.3 1.56e+02 3.7 8.21e-04 3.62e-03h 1\n", + " 27r 0.0000000e+00 3.85e+05 3.16e+05 2.3 1.55e+02 5.1 1.83e-02 6.41e-04h 1\n", + " 28r 0.0000000e+00 3.82e+05 3.30e+05 2.3 1.55e+02 4.6 1.40e-02 1.11e-02h 1\n", + " 29r 0.0000000e+00 3.81e+05 7.08e+05 2.3 1.53e+02 5.0 2.85e-02 4.20e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30r 0.0000000e+00 3.72e+05 7.46e+05 2.3 1.53e+02 4.5 4.86e-02 3.45e-02h 1\n", + " 31r 0.0000000e+00 3.67e+05 1.89e+06 2.3 1.47e+02 5.0 1.12e-01 2.04e-02h 1\n", + " 32r 0.0000000e+00 3.24e+05 1.59e+06 2.3 1.44e+02 4.5 1.96e-01 1.79e-01h 1\n", + " 33r 0.0000000e+00 3.23e+05 1.58e+06 2.3 1.19e+02 4.0 4.52e-03 5.61e-03h 1\n", + " 34r 0.0000000e+00 2.94e+05 1.59e+06 2.3 1.18e+02 4.4 3.45e-01 1.47e-01h 1\n", + " 35r 0.0000000e+00 2.80e+05 1.53e+06 2.3 1.01e+02 4.0 1.38e-01 8.76e-02h 1\n", + " 36r 0.0000000e+00 2.52e+05 1.66e+06 2.3 9.17e+01 4.4 3.38e-01 1.83e-01h 1\n", + " 37r 0.0000000e+00 2.39e+05 1.55e+06 2.3 7.50e+01 3.9 9.13e-01 1.05e-01h 1\n", + " 38r 0.0000000e+00 2.13e+05 1.24e+06 2.3 6.72e+01 3.4 5.58e-01 2.28e-01h 1\n", + " 39r 0.0000000e+00 1.95e+05 1.05e+06 2.3 5.18e+01 3.9 1.00e+00 2.15e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40r 0.0000000e+00 1.28e+05 2.34e+05 2.3 4.08e+01 3.4 5.49e-01 1.00e+00h 1\n", + " 41r 0.0000000e+00 1.28e+05 2.87e+05 2.3 8.85e-01 2.9 5.24e-01 9.02e-01f 1\n", + " 42r 0.0000000e+00 1.28e+05 1.76e+05 2.3 3.90e-01 4.2 3.08e-01 9.59e-01f 1\n", + " 43r 0.0000000e+00 1.28e+05 5.03e+04 2.3 1.25e-01 3.8 3.19e-01 1.00e+00f 1\n", + " 44r 0.0000000e+00 1.28e+05 4.94e+04 2.3 4.82e+00 3.3 1.85e-02 1.19e-01f 2\n", + " 45r 0.0000000e+00 1.28e+05 1.37e+04 2.3 3.62e-01 3.7 8.33e-01 1.00e+00f 1\n", + " 46r 0.0000000e+00 1.28e+05 7.07e+03 1.6 5.21e-01 3.2 8.97e-01 1.00e+00f 1\n", + " 47r 0.0000000e+00 1.29e+05 5.44e+02 1.6 9.53e-01 2.8 8.34e-01 8.12e-01f 1\n", + " 48r 0.0000000e+00 1.29e+05 8.91e+02 0.9 2.85e+00 2.3 4.12e-01 2.43e-01f 1\n", + " 49r 0.0000000e+00 1.30e+05 6.99e+02 0.9 8.46e+00 1.8 7.74e-01 2.05e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50r 0.0000000e+00 1.31e+05 3.95e+04 0.9 2.41e+01 1.3 1.00e+00 1.51e-01f 1\n", + " 51r 0.0000000e+00 1.30e+05 4.66e+04 0.9 7.23e+01 0.8 1.00e+00 5.24e-02f 1\n", + " 52r 0.0000000e+00 1.18e+05 3.45e+04 0.9 2.17e+02 0.4 6.96e-01 1.67e-01f 1\n", + " 53r 0.0000000e+00 1.17e+05 1.74e+04 0.9 6.50e+02 -0.1 1.43e-01 1.50e-02f 1\n", + " 54r 0.0000000e+00 1.17e+05 4.23e+04 0.9 1.94e+03 -0.6 6.50e-01 3.25e-02f 1\n", + " 55r 0.0000000e+00 1.18e+05 5.54e+04 0.9 3.69e+03 -1.1 4.70e-01 9.48e-03f 1\n", + " 56r 0.0000000e+00 1.25e+05 2.75e+04 0.9 1.01e+02 -1.5 7.89e-01 1.78e-01f 1\n", + " 57r 0.0000000e+00 1.28e+05 2.68e+04 0.9 9.57e+01 -2.0 9.34e-01 1.60e-01f 1\n", + " 58r 0.0000000e+00 1.37e+05 5.37e+02 0.9 2.51e+02 -2.5 1.00e+00 6.23e-01f 1\n", + " 59r 0.0000000e+00 1.40e+05 1.78e+04 0.2 7.53e+02 -3.0 4.51e-01 6.22e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60r 0.0000000e+00 1.40e+05 1.99e+03 0.2 2.25e+03 -3.4 6.57e-01 3.90e-01f 1\n", + " 61r 0.0000000e+00 1.40e+05 6.25e+04 0.2 8.45e+02 -3.0 1.00e+00 2.93e-01f 1\n", + " 62r 0.0000000e+00 1.40e+05 4.84e+04 0.2 2.48e+03 -3.5 1.00e+00 2.59e-01f 1\n", + " 63r 0.0000000e+00 1.40e+05 9.09e+04 0.2 8.10e+02 -4.0 5.18e-01 4.12e-02f 1\n", + " 64r 0.0000000e+00 1.40e+05 4.52e+03 0.2 3.19e+02 -3.6 5.90e-01 8.39e-01f 1\n", + " 65r 0.0000000e+00 1.40e+05 9.20e+03 0.2 8.45e+02 -4.0 2.58e-01 3.11e-01f 1\n", + " 66r 0.0000000e+00 1.40e+05 9.35e+02 0.2 2.32e+03 -4.5 9.50e-02 5.05e-01f 1\n", + " 67r 0.0000000e+00 1.40e+05 1.80e+03 0.2 3.94e+03 -5.0 1.00e+00 6.61e-02f 1\n", + " 68r 0.0000000e+00 1.40e+05 2.93e+03 0.2 4.85e+03 -5.5 9.99e-01 2.84e-01f 1\n", + " 69r 0.0000000e+00 1.38e+05 6.05e+03 0.2 6.81e+03 -5.9 1.00e+00 2.40e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70r 0.0000000e+00 1.37e+05 1.78e+03 0.2 2.85e+03 -5.5 1.00e+00 1.00e+00f 1\n", + " 71r 0.0000000e+00 1.34e+05 1.31e+03 0.2 8.14e+03 -6.0 3.19e-01 3.05e-01f 1\n", + " 72r 0.0000000e+00 1.31e+05 1.83e+03 0.2 2.65e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 73r 0.0000000e+00 1.28e+05 3.42e+03 0.2 1.45e+04 -6.0 1.00e+00 2.70e-01f 1\n", + " 74r 0.0000000e+00 1.24e+05 1.09e+01 0.2 4.06e+03 -5.6 1.00e+00 1.00e+00f 1\n", + " 75r 0.0000000e+00 1.05e+05 7.56e+03 -0.5 5.64e+04 -6.1 2.15e-01 3.59e-01f 1\n", + " 76r 0.0000000e+00 1.05e+05 1.79e+04 -0.5 2.46e+03 -4.8 5.42e-01 1.26e-01f 1\n", + " 77r 0.0000000e+00 1.05e+05 2.30e+04 -0.5 9.93e+03 -5.2 1.04e-02 6.09e-02f 1\n", + " 78r 0.0000000e+00 1.05e+05 1.44e+03 -0.5 2.90e+03 -4.8 1.16e-01 1.32e-02f 1\n", + " 79r 0.0000000e+00 1.04e+05 8.21e+04 -0.5 9.44e+03 -5.3 4.02e-02 1.19e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80r 0.0000000e+00 1.04e+05 4.46e+03 -0.5 1.93e+03 -4.9 2.08e-01 2.98e-02f 1\n", + " 81r 0.0000000e+00 9.40e+04 1.37e+05 -0.5 1.15e+04 -5.3 5.49e-03 2.67e-01f 1\n", + " 82r 0.0000000e+00 9.39e+04 1.21e+05 -0.5 2.56e+03 -4.9 3.04e-01 9.74e-03f 1\n", + " 83r 0.0000000e+00 9.25e+04 1.08e+05 -0.5 4.97e+03 -5.4 1.59e-01 1.20e-01f 1\n", + " 84r 0.0000000e+00 9.25e+04 1.35e+05 -0.5 8.51e+03 -5.9 5.44e-01 3.08e-02f 1\n", + " 85r 0.0000000e+00 1.04e+05 1.06e+05 -0.5 1.26e+04 -6.3 1.73e-01 4.10e-01f 1\n", + " 86r 0.0000000e+00 1.08e+05 1.45e+05 -0.5 2.50e+04 -6.8 1.23e-01 7.63e-02f 1\n", + " 87r 0.0000000e+00 1.07e+05 1.40e+05 -0.5 4.68e+02 -2.8 3.12e-02 1.16e-01h 1\n", + " 88r 0.0000000e+00 1.07e+05 1.34e+05 -0.5 1.25e+02 -2.4 1.37e-01 6.14e-02h 1\n", + " 89r 0.0000000e+00 1.05e+05 1.21e+05 -0.5 6.38e+01 -1.9 4.82e-02 1.54e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r 0.0000000e+00 1.04e+05 1.11e+05 -0.5 2.62e+01 -1.5 9.28e-02 1.14e-01h 1\n", + " 91r 0.0000000e+00 1.02e+05 8.74e+04 -0.5 2.58e+01 -2.0 1.72e-01 2.50e-01h 1\n", + " 92r 0.0000000e+00 1.02e+05 7.56e+04 -0.5 2.13e+01 -1.6 3.40e-01 1.09e-01f 1\n", + " 93r 0.0000000e+00 1.02e+05 5.81e+04 -0.5 9.06e+00 -2.0 6.37e-01 2.34e-01h 1\n", + " 94r 0.0000000e+00 1.02e+05 3.30e+04 -0.5 2.09e+01 -2.5 1.00e+00 4.49e-01h 1\n", + " 95r 0.0000000e+00 1.01e+05 2.02e+03 -0.5 9.58e+01 -3.0 4.65e-01 8.13e-01f 1\n", + " 96r 0.0000000e+00 1.02e+05 1.56e+04 -0.5 8.77e+01 -3.5 7.24e-01 1.53e-01f 1\n", + " 97r 0.0000000e+00 1.02e+05 5.99e+03 -0.5 2.31e+02 -3.9 3.97e-01 4.89e-01f 1\n", + " 98r 0.0000000e+00 1.04e+05 4.62e+03 -0.5 4.75e+02 -4.4 6.42e-01 1.95e-01f 1\n", + " 99r 0.0000000e+00 1.04e+05 9.76e+02 -0.5 8.15e+02 -4.9 7.06e-01 6.61e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r 0.0000000e+00 1.05e+05 7.45e+03 -0.5 2.44e+03 -5.4 1.00e+00 1.91e-01f 1\n", + " 101r 0.0000000e+00 1.06e+05 1.94e+03 -0.5 7.23e+02 -4.9 1.00e+00 3.62e-01f 1\n", + " 102r 0.0000000e+00 1.07e+05 7.40e+03 -0.5 1.49e+03 -5.4 1.00e+00 4.66e-01f 1\n", + " 103r 0.0000000e+00 1.08e+05 3.03e+03 -0.5 1.66e+03 -5.9 8.96e-01 8.34e-01f 1\n", + " 104r 0.0000000e+00 1.10e+05 5.48e+02 -0.5 9.38e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 105r 0.0000000e+00 1.10e+05 1.76e+02 -0.5 1.46e+03 -6.0 7.45e-01 1.00e+00f 1\n", + " 106r 0.0000000e+00 1.10e+05 7.27e+01 -0.5 6.32e+02 -5.5 1.00e+00 1.00e+00f 1\n", + " 107r 0.0000000e+00 1.11e+05 1.41e+03 -0.5 1.49e+03 -6.0 1.00e+00 9.82e-01f 1\n", + " 108r 0.0000000e+00 1.12e+05 1.04e+03 -0.5 3.05e+03 -6.5 1.00e+00 4.21e-01f 1\n", + " 109r 0.0000000e+00 1.12e+05 3.92e+02 -0.5 7.12e+03 -7.0 8.81e-01 5.45e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110r 0.0000000e+00 1.12e+05 6.27e+02 -0.5 1.40e+04 -7.4 1.00e+00 2.04e-01f 1\n", + " 111r 0.0000000e+00 1.27e+05 1.93e+02 -0.5 2.11e+04 -7.9 7.01e-01 6.92e-01f 1\n", + " 112r 0.0000000e+00 1.51e+05 1.49e+02 -0.5 2.24e+04 -8.4 4.24e-01 4.78e-01f 1\n", + " 113r 0.0000000e+00 1.28e+05 1.63e+01 -0.5 2.40e+04 -8.9 1.00e+00 1.00e+00f 1\n", + " 114r 0.0000000e+00 1.36e+05 3.29e+02 -0.5 4.21e+04 -9.3 6.45e-01 1.00e+00f 1\n", + " 115r 0.0000000e+00 5.01e+05 1.31e+03 -0.5 9.66e+04 -9.8 9.22e-01 1.00e+00h 1\n", + " 116r 0.0000000e+00 8.78e+05 4.66e+02 -0.5 2.96e+05 -10.3 9.46e-01 1.00e+00h 1\n", + " 117r 0.0000000e+00 6.70e+04 4.18e+02 -0.5 9.60e+05 -10.8 1.00e+00 1.00e+00h 1\n", + " 118r 0.0000000e+00 5.21e+04 9.75e+02 -0.5 3.82e+06 -11.3 1.00e+00 7.10e-01f 1\n", + " 119r 0.0000000e+00 5.30e+04 9.97e+02 -0.5 9.41e+06 - 8.43e-02 2.44e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120r 0.0000000e+00 5.40e+04 9.62e+02 -0.5 2.95e+06 - 1.00e+00 1.41e-01f 1\n", + " 121r 0.0000000e+00 5.13e+04 5.63e+01 -0.5 1.96e+05 - 1.00e+00 1.00e+00f 1\n", + " 122r 0.0000000e+00 5.06e+04 7.06e-01 -0.5 1.45e+04 - 1.00e+00 1.00e+00h 1\n", + " 123r 0.0000000e+00 4.48e+04 1.60e+01 -2.9 1.41e+04 - 8.33e-01 7.83e-01f 1\n", + " 124r 0.0000000e+00 7.43e+04 1.23e+02 -2.9 1.09e+05 -9.9 1.51e-01 1.14e-01f 1\n", + " 125r 0.0000000e+00 7.21e+04 3.54e+02 -2.9 1.66e+05 - 1.51e-01 3.48e-02h 1\n", + " 126r 0.0000000e+00 4.03e+04 3.48e+02 -2.9 6.43e+04 - 4.59e-01 5.71e-01f 1\n", + " 127r 0.0000000e+00 9.43e+03 9.62e+01 -2.9 2.75e+04 - 5.72e-01 8.74e-01h 1\n", + " 128r 0.0000000e+00 7.66e+03 2.89e+02 -2.9 4.00e+03 - 7.38e-01 1.00e+00h 1\n", + " 129r 0.0000000e+00 8.78e+02 2.90e+01 -2.9 1.50e+03 - 9.18e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 130r 0.0000000e+00 7.37e+02 1.27e+01 -2.9 1.32e+03 - 1.00e+00 1.00e+00h 1\n", + " 131r 0.0000000e+00 3.66e+02 6.41e+00 -2.9 9.22e+02 - 1.00e+00 1.00e+00h 1\n", + " 132r 0.0000000e+00 8.13e+00 2.77e-02 -2.9 6.19e+01 - 1.00e+00 1.00e+00h 1\n", + " 133r 0.0000000e+00 7.03e+03 1.41e+01 -4.3 5.16e+03 - 7.78e-01 7.77e-01f 1\n", + " 134r 0.0000000e+00 5.08e+03 4.30e+02 -4.3 3.71e+03 - 1.00e+00 7.18e-01h 1\n", + " 135r 0.0000000e+00 2.02e+02 2.79e+01 -4.3 6.26e+02 - 1.00e+00 1.00e+00h 1\n", + " 136r 0.0000000e+00 1.50e+01 2.52e+00 -4.3 1.46e+02 - 1.00e+00 1.00e+00h 1\n", + " 137r 0.0000000e+00 8.83e-01 1.86e-02 -4.3 1.27e+01 - 1.00e+00 1.00e+00h 1\n", + " 138r 0.0000000e+00 7.60e-01 3.09e-05 -4.3 1.51e+00 - 1.00e+00 1.00e+00h 1\n", + " 139 0.0000000e+00 7.60e-01 1.08e+06 -1.0 8.24e+02 - 9.89e-01 7.57e-06h 17\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 140 0.0000000e+00 7.60e-01 1.94e+06 -1.0 8.24e+02 - 9.90e-01 1.89e-06h 19\n", + " 141 0.0000000e+00 2.27e+02 9.80e+05 -1.0 8.24e+02 - 4.96e-01 4.96e-01s 21\n", + " 142r 0.0000000e+00 2.27e+02 1.00e+03 -1.0 0.00e+00 - 0.00e+00 0.00e+00R 1\n", + " 143r 0.0000000e+00 2.20e+02 1.07e+04 -1.0 2.63e+04 - 2.05e-01 5.61e-03f 1\n", + " 144r 0.0000000e+00 2.03e+03 1.87e+03 -1.0 2.78e+04 - 9.30e-01 2.21e-01f 1\n", + " 145r 0.0000000e+00 1.09e+04 2.99e+03 -1.0 1.86e+04 - 3.04e-01 6.48e-01f 1\n", + " 146r 0.0000000e+00 1.30e+04 1.58e+03 -1.0 1.46e+05 - 2.04e-01 3.61e-01f 1\n", + " 147r 0.0000000e+00 1.36e+04 3.08e+02 -1.0 1.18e+04 - 9.12e-01 1.00e+00f 1\n", + " 148r 0.0000000e+00 1.10e+04 2.16e+00 -1.0 4.09e+00 -4.0 1.00e+00 1.00e+00h 1\n", + " 149r 0.0000000e+00 1.22e+04 1.65e+00 -1.7 2.94e+01 -4.5 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 150r 0.0000000e+00 1.31e+04 1.64e+00 -1.7 5.03e+01 -5.0 1.00e+00 1.00e+00f 1\n", + " 151r 0.0000000e+00 1.29e+04 3.23e+00 -1.7 3.50e+01 -5.4 1.00e+00 1.00e+00h 1\n", + " 152r 0.0000000e+00 1.19e+04 5.44e+02 -1.7 3.69e+04 - 1.00e+00 6.74e-01f 1\n", + " 153r 0.0000000e+00 3.43e+03 2.19e+01 -1.7 1.23e+04 - 1.00e+00 1.00e+00h 1\n", + " 154r 0.0000000e+00 2.96e+03 5.24e-01 -1.7 1.78e+03 - 1.00e+00 1.00e+00h 1\n", + " 155r 0.0000000e+00 2.99e+03 2.57e+01 -2.5 1.05e+04 - 8.24e-01 8.54e-01f 1\n", + " 156r 0.0000000e+00 4.83e+03 2.10e+01 -2.5 3.56e+03 - 1.00e+00 9.28e-01h 1\n", + " 157r 0.0000000e+00 1.91e+02 6.11e+00 -2.5 7.38e+02 - 1.00e+00 1.00e+00h 1\n", + " 158r 0.0000000e+00 6.34e+01 3.88e-02 -2.5 7.32e+01 - 1.00e+00 1.00e+00h 1\n", + " 159r 0.0000000e+00 1.16e+04 1.91e+02 -3.8 5.52e+03 - 7.33e-01 9.36e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 160r 0.0000000e+00 8.60e+03 5.01e+02 -3.8 4.56e+03 - 3.35e-01 3.58e-01h 1\n", + " 161r 0.0000000e+00 4.61e+03 2.92e+03 -3.8 2.07e+03 - 8.26e-01 5.26e-01h 1\n", + " 162r 0.0000000e+00 3.60e+02 8.99e+03 -3.8 8.68e+02 - 5.05e-01 1.00e+00h 1\n", + " 163r 0.0000000e+00 1.13e+02 3.07e+02 -3.8 5.08e+02 - 1.00e+00 1.00e+00h 1\n", + " 164r 0.0000000e+00 1.67e+02 3.30e+01 -3.8 6.12e+02 - 1.00e+00 1.00e+00h 1\n", + " 165r 0.0000000e+00 1.22e+01 1.46e-01 -3.8 1.59e+02 - 1.00e+00 1.00e+00h 1\n", + " 166r 0.0000000e+00 2.15e+00 1.25e-03 -3.8 1.80e+01 - 1.00e+00 1.00e+00h 1\n", + " 167r 0.0000000e+00 6.62e+02 3.07e+02 -5.7 2.03e+03 - 9.26e-01 5.74e-01f 1\n", + " 168r 0.0000000e+00 4.94e+02 1.08e+02 -5.7 1.15e+03 - 1.00e+00 7.82e-01h 1\n", + " 169r 0.0000000e+00 4.16e+02 2.06e+02 -5.7 6.08e+02 - 9.82e-01 1.68e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 170r 0.0000000e+00 3.63e+02 1.05e+04 -5.7 1.90e+02 - 1.00e+00 9.40e-01h 1\n", + " 171r 0.0000000e+00 4.94e+03 1.45e+05 -5.7 6.81e+00 - 1.00e+00 9.80e-02h 1\n", + " 172r 0.0000000e+00 5.01e+03 1.47e+05 -5.7 3.34e-01 - 1.00e+00 1.00e+00f 1\n", + " 173r 0.0000000e+00 3.29e+03 2.38e+05 -5.7 4.37e-01 - 1.00e+00 1.00e+00H 1\n", + " 174r 0.0000000e+00 1.30e+03 9.35e+04 -5.7 5.77e-01 - 1.00e+00 2.87e-01h 2\n", + " 175r 0.0000000e+00 2.20e+02 1.60e+04 -5.7 9.32e-02 - 1.00e+00 1.00e+00h 1\n", + " 176r 0.0000000e+00 2.98e+01 2.17e+03 -5.7 3.88e-02 - 9.67e-01 1.00e+00h 1\n", + " 177 0.0000000e+00 2.58e+01 8.80e+06 -1.0 4.77e-01 - 9.90e-01 1.00e+00f 1\n", + " 178 0.0000000e+00 5.64e+00 1.91e+06 -1.0 9.74e-02 - 9.90e-01 1.00e+00h 1\n", + " 179 0.0000000e+00 2.20e-04 3.75e+03 -1.0 5.06e-06 - 9.92e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 180 0.0000000e+00 7.45e-09 1.06e-02 -2.5 1.31e-07 - 1.00e+00 1.00e+00h 1\n", + " 181 0.0000000e+00 2.24e-08 2.57e-04 -7.0 1.06e-07 - 1.00e+00 1.00e+00h 1\n", + " 182 0.0000000e+00 2.24e-08 3.90e-11 -7.0 9.85e-08 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 182\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 3.8958489431350689e-11 3.8958489431350689e-11\n", + "Constraint violation....: 2.9103830456733704e-11 2.2351741790771484e-08\n", + "Variable bound violation: 2.8593320084580268e-14 2.8593320084580268e-14\n", + "Complementarity.........: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "Overall NLP error.......: 9.0909090909090994e-08 9.0909090909090994e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 253\n", + "Number of objective gradient evaluations = 22\n", + "Number of equality constraint evaluations = 253\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 185\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 182\n", + "Total seconds in IPOPT = 0.150\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Check physical units consistency, solve and check solver status\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.util.check_units import assert_units_consistent\n", + "\n", + "assert_units_consistent(m)\n", + "results = solver.solve(m, tee=True, symbolic_solver_labels=True)\n", + "assert results.solver.termination_condition == TerminationCondition.optimal" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For comparison, we will call and build the HDA flowsheet replacing the second `Flash` with a `TrayColumn` distillation unit model. The flowsheet costing occurs in the external script `hda_flowsheets_for_costing_notebook.py` and is not shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Building flowsheet...\n", + "\n", + "Setting inputs...\n", + "\n", + "Initializing flowsheet...\n", + "\n", + "Limiting Wegstein tear to 3 iterations to obtain initial solution, if not converged IPOPT will pick up and continue.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:49 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:50 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:48:51 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:52 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:53 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:54 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.79176447139432e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:55 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:56 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.552218344889833e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.552202058782412e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:57 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_in: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.H101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.R101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.R101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:58 [INFO] idaes.init.fs.F101.control_volume.properties_in: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 25 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.F101.control_volume.properties_out: Initialization Complete\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,methane]'\n", + "to a numeric value `9.718163551136042e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "WARNING (W1002): Setting Var\n", + "'fs.F101.control_volume.properties_in[0.0].flow_mol_phase_comp[Liq,hydrogen]'\n", + "to a numeric value `9.718389797696418e-13` outside the bounds (1e-12, 100).\n", + " See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.purge_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101.recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_in: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.C101.control_volume.properties_out: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.toluene_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.hydrogen_feed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.vapor_recycle_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101.mixed_state: Initialization Complete\n", + "2026-07-22 11:48:59 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2026-07-22 11:49:00 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2026-07-22 11:49:01 [INFO] idaes.init.fs.H102.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Solving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Adding distillation column and resolving flowsheet...\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 17\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 5\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 10\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 11\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Complete.\n", + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 150 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n" + ] + } + ], + "source": [ + "from pyomo.common.log import LoggingIntercept\n", + "import logging\n", + "from io import StringIO\n", + "\n", + "stream = StringIO()\n", + "with LoggingIntercept(stream, \"idaes\", logging.WARNING):\n", + " # Source file for prebuilt flowsheets\n", + " from hda_flowsheets_for_costing_notebook import hda_with_distillation\n", + "\n", + " # Build hda model with distillation column and return model object\n", + " n = hda_with_distillation(tee=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Results Comparison and Visualization\n", + "For the two flowsheets above, let's sum the total operating and capital costs of each scenario. We will display overall process economics results and compare the two flowsheets:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Imports and data gathering\n", + "from matplotlib import pyplot as plt\n", + "\n", + "plt.style.use(\"dark_background\") # if using browser in dark mode, uncomment this line\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "# Automatically get units that we costed - this will exclude C101 for both flowsheets\n", + "\n", + "two_flash_unitlist = [\n", + " getattr(m.fs, unit) for unit in dir(m.fs) if hasattr(getattr(m.fs, unit), \"costing\")\n", + "]\n", + "distillation_unitlist = [\n", + " getattr(n.fs, unit) for unit in dir(n.fs) if hasattr(getattr(n.fs, unit), \"costing\")\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Equipmentfs.H101fs.R101fs.F101fs.F102fs.D101fs.H102
Distillation13.28333413.5522947.7813320.0000007.607433.32944
Two Flash13.28333410.7558787.7813327.7813320.000000.00000
\n", + "
" + ], + "text/plain": [ + "Equipment fs.H101 fs.R101 fs.F101 fs.F102 fs.D101 fs.H102\n", + "Distillation 13.283334 13.552294 7.781332 0.000000 7.60743 3.32944\n", + "Two Flash 13.283334 10.755878 7.781332 7.781332 0.00000 0.00000" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Compare equipment purchase costs (actual capital costs)\n", + "\n", + "two_flash_capcost = {\n", + " unit.name: value(unit.costing.capital_cost / 1e3) for unit in two_flash_unitlist\n", + "}\n", + "distillation_capcost = {\n", + " unit.name: value(unit.costing.capital_cost / 1e3) for unit in distillation_unitlist\n", + "}\n", + "\n", + "two_flash_capdf = pd.DataFrame(\n", + " list(two_flash_capcost.items()), columns=[\"Equipment\", \"Two Flash\"]\n", + ").set_index(\"Equipment\")\n", + "distillation_capdf = pd.DataFrame(\n", + " list(distillation_capcost.items()), columns=[\"Equipment\", \"Distillation\"]\n", + ").set_index(\"Equipment\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "capcosts = two_flash_capdf.add(distillation_capdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "# Sort according to an easier order to view\n", + "capcosts = capcosts[[\"fs.H101\", \"fs.R101\", \"fs.F101\", \"fs.F102\", \"fs.D101\", \"fs.H102\"]]\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(capcosts) # view dataframe before plotting\n", + "\n", + "capplot = capcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Total Capital Costs\", ylabel=\"$1000\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Utilitiescoolingheating
Distillation60.192008367.404722
Two Flash47.028803372.093536
\n", + "
" + ], + "text/plain": [ + "Utilities cooling heating\n", + "Distillation 60.192008 367.404722\n", + "Two Flash 47.028803 372.093536" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Compare operating costs (per year)\n", + "\n", + "two_flash_opcost = {\n", + " \"cooling\": value(3600 * 24 * 365 * m.fs.cooling_cost / 1e3),\n", + " \"heating\": value(3600 * 24 * 365 * m.fs.heating_cost / 1e3),\n", + "}\n", + "distillation_opcost = {\n", + " \"cooling\": value(3600 * 24 * 365 * n.fs.cooling_cost / 1e3),\n", + " \"heating\": value(3600 * 24 * 365 * n.fs.heating_cost / 1e3),\n", + "}\n", + "\n", + "two_flash_opdf = pd.DataFrame(\n", + " list(two_flash_opcost.items()), columns=[\"Utilities\", \"Two Flash\"]\n", + ").set_index(\"Utilities\")\n", + "distillation_opdf = pd.DataFrame(\n", + " list(distillation_opcost.items()), columns=[\"Utilities\", \"Distillation\"]\n", + ").set_index(\"Utilities\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "opcosts = two_flash_opdf.add(distillation_opdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(opcosts) # view dataframe before plotting\n", + "\n", + "opplot = opcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Operating Costs\", ylabel=\"$1000/year\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Costs in $1000:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Costscapitaloperating
Distillation45.553829427.596731
Two Flash39.601876419.122339
\n", + "
" + ], + "text/plain": [ + "Costs capital operating\n", + "Distillation 45.553829 427.596731\n", + "Two Flash 39.601876 419.122339" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAHvCAYAAABQTQWGAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOyVJREFUeJzt3Qd40+X+//93W1pEaJlSoEyZhyUoyFAQBARBZCkOQIGjMhQXKoILxzmAylBQ4QgoIoKIAoIoKFPZQ7HsvUcBmWVD/tf7/v6TX1M6krY0zf15Pq4rVzPupHc+SZpX7xkiIi4BAACwWGigKwAAAHC9EXgAAID1CDwAAMB6BB4AAGA9Ag8AALAegQcAAFiPwAMAAKxH4AEAANYj8AC4rj788EN57rnnsuzjOdnLL78sPXv2lKwiJCRERo4cKU2aNAl0VWChEFZaBnzXq1cvqVu3rjz66KPicl27SPmIESPkn3/+kTfffPOa+yi9z9mzZ+XYsWOybt06+eWXX+TIkSMp/s5PPvlE8uXLJ//5z3/MfVKjYaB27dqpltu1a5f07ds3xTIff/yxbN26VYYPHy5ptXHjRlPvBx98MMVy77zzjpQtW9Zz+fz587J9+3b57rvvZPPmzX4/Xnql9blHRkZK69atpUaNGpI7d26Ji4szz+OHH35I9bXOzLpWqVJF1qxZI3feeacsX75c2rVrJw888ECq97ty5Yp07NjR59fL3+Py1ltvSadOneRf//qXXLp0yefnA6SGFh7ADxpcHn74YQkNTfqj06pVq2v+O3Xf58cff5Tp06fLokWL5OTJk/Lvf/9b9u3bZ76kbrjhhiQfT4OL/geuX0RPP/20T3VcuXKlTJs2zXPauXOn+f1nzpzxun7+/PmpPlbLli09Ye160+OmJ3f9Vq1aZX5/bGysPP7445LZ0vLcNQjv3r1bevfuLYcPH5a5c+ean507d5a9e/ean1mlru+99578/vvvJuyoTZs2eb0/9H2q75u8efN6Xa/vYX9fL3+Oy7BhwyQmJkaeeOKJDDk2QEL6byonjgHvAR/eAxMnTnSpsLCwJG/fu3eva+nSpT7f54EHHnBdunTJNWXKlCQfb/To0eYxP/zwQ9eJEydcN954o9+vU9OmTc3v79atm9/33blzp6l/ej4fGzdudH333XepltPjps814XURERGurVu3uk6ePOnKnj27X4+X3pO/z71du3bmOA8bNizJ27t37+56/fXXs0Rdixcv7rp8+bLrscceS7ZMTEyMeT7Dhw9P1+uVluMyefJkV2xs7HV/jTmJo45BNq/oAyBTTZkyRe666y555plnpH79+ua/ardcuXLJQw89JO+//76MHz9enn/+eWnfvr18+eWXGfK7S5UqZbomSpcubVp/tMVHuxfcXXUTJ06Um266SerUqWPOJ+4Ge+ONN6RixYqebg7tlpg3b57MmDFDMsrFixfNYz711FNSvnx5+fvvv5Ms52tdPvvsM1m7dq2MHTvWtCBo94qWHT16tOkSckvtuScWHh4uH330kelue/HFF5Mso2NToqKi/HoN3F1B2sVTqVIlM8ZFu/O++uorUz4tdVX6vgoLC8vQ1yqp10uPR1qOi7aGapeldrtpixGQEejSAgJswoQJnu6wxN0A2bNnN1/G+gU2e/ZsefLJJzPkd+pYig0bNpiQtWzZMjPu6IsvvpDffvtNIiIiTBntptDxRvv370+yG+yPP/7wXD9nzhy5fPmyfP311/L5559LRtLgp86dO5dsGV/ros9bu34mTZok0dHRpjunQYMGpjumZMmSnnKpPffE9DhqN8w333wjV69eTbbcqVOn/HoN8ufPbwJaly5dTGhYvXq1lCtXzoy9cR8Xf+uq9Dlv2bJFjh8/Lhkt4euVluOili5dan42bNgww+sHZwt4MxMnjkGwvAfc3VOTJk0y5xOf4uPj/erS0lOePHnM7TNmzPC6fsWKFaZp3325RYsWplzFihXT1aWlv0+7HH755RdXSEiIp1y9evVMuf79+6e5q6R169bmMapWrZohXVrlypVznTp1yrVp0ya/Hy+puhw8eNB15swZV61atTzXRUVFuU6fPu0aMWKE1/39ee7PPfec+V36O30p7+tr0LlzZ3M5Ojra6/758+d3hYeHp/l10vKzZs1KsUxaurQSv17+Hhf3SY/JlStXXKNGjfLrfpw4BpLCMaBLC0gDHbiZ1H+saZlO6265uPHGGz3X3XLLLVKzZk155ZVXPNfNmjXLDEDWrpjkugd80aJFC9OFoINDE3ad6ADWFStWmJal/v37p/o42r2ig1S1S65gwYKSLVs2z3OoWrVqst1PKdHZaO5uGW3d0BlE+py1Cyaj6qJdQu6Buu7WBX3e1apVk7TKmTNnqq1Q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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Compare total costs (capital costs and operating costs)\n", + "\n", + "two_flash_totcost = {\n", + " \"capital\": sum(two_flash_capcost[idx] for idx in two_flash_capcost),\n", + " \"operating\": value(m.fs.operating_cost) / 1e3,\n", + "}\n", + "distillation_totcost = {\n", + " \"capital\": sum(distillation_capcost[idx] for idx in distillation_capcost),\n", + " \"operating\": value(n.fs.operating_cost) / 1e3,\n", + "}\n", + "\n", + "two_flash_totdf = pd.DataFrame(\n", + " list(two_flash_totcost.items()), columns=[\"Costs\", \"Two Flash\"]\n", + ").set_index(\"Costs\")\n", + "distillation_totdf = pd.DataFrame(\n", + " list(distillation_totcost.items()), columns=[\"Costs\", \"Distillation\"]\n", + ").set_index(\"Costs\")\n", + "\n", + "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", + "totcosts = two_flash_totdf.add(distillation_totdf, fill_value=0).fillna(0).transpose()\n", + "\n", + "print(\"Costs in $1000:\")\n", + "display(totcosts) # view dataframe before plotting\n", + "\n", + "totplot = totcosts.plot(\n", + " kind=\"bar\", stacked=True, title=\"HDA Total Plant Cost (TPC)\", ylabel=\"$1000/year\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's compare the total costs on a production basis. This will account for the greater efficiency provided by the distillation column relative to the less-expensive second flash unit:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Two flash case over one year: $459K / 4477 kmol benzene = $102.45 per kmol benzene produced\n", + "Distillation case over one year: $473K / 5108 kmol benzene = $92.63 per kmol benzene produced\n" + ] + } + ], + "source": [ + "two_flash_cost = value(1e3 * sum(two_flash_totcost[idx] for idx in two_flash_totcost))\n", + "two_flash_prod = value(\n", + " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] * 365 * 24 * 3600\n", + ")\n", + "distillation_cost = value(\n", + " 1e3 * sum(distillation_totcost[idx] for idx in distillation_totcost)\n", + ")\n", + "distillation_prod = value(n.fs.D101.condenser.distillate.flow_mol[0] * 365 * 24 * 3600)\n", + "\n", + "print(\n", + " f\"Two flash case over one year: ${two_flash_cost/1e3:0.0f}K / {two_flash_prod/1e3:0.0f} kmol benzene = ${two_flash_cost/(two_flash_prod/1e3):0.2f} per kmol benzene produced\"\n", + ")\n", + "print(\n", + " f\"Distillation case over one year: ${distillation_cost/1e3:0.0f}K / {distillation_prod/1e3:0.0f} kmol benzene = ${distillation_cost/(distillation_prod/1e3):0.2f} per kmol benzene produced\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Summary\n", + "In this example, IDAES Process Costing Framework methods were applied to two HDA flowsheets for capital cost estimation. The costing blocks calls showcased multiple methods to define unit costing, demonstrating the flexibility and best practice of the costing framework. In the basic examples, the two-flash HDA did not include costing and the distillation HDA estimated a reactor capital cost comprising 3.3% of the total plant cost (TPC). With more rigorous costing, IDAES obtained total capital costs of 8.5% TPC (two flash HDA) and 9.6% (distillation HDA) and better modeled the impact of equipment cost on process economics. As printed above, the IDAES Process Costing Framework confirmed that replacing the second flash drum with a distillation column results in increased equipment costs, increased production and decreased cost per unit product." + ] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" + } }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "# HDA Flowsheet Costing\n", - "Maintainer: Brandon Paul \n", - "Author: Brandon Paul \n", - "Updated: 2023-06-01 \n", - "\n", - "\n", - "## Note\n", - "\n", - "This example will demonstrate adding capital and operating costs to the two HDA examples, the basic [HDA with Flash](../tut/hda_flowsheet_solution_usr.ipynb) and a comparison with the HDA with Distillation.\n", - "\n", - "\n", - "## Learning outcomes\n", - "\n", - "- Import external pre-built steady-state flowsheets using the IDAES unit model library\n", - "- Define and add costing blocks using the IDAES Process Costing Framework\n", - "- Formulate and solve a process economics optimization problem\n", - " - Defining an objective function\n", - " - Setting variable bounds\n", - " - Adding additional constraints \n", - "\n", - "\n", - "## Problem Statement\n", - "\n", - "Hydrodealkylation is a chemical reaction that often involves reacting\n", - "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", - "simpler aromatic hydrocarbon devoid of functional groups. In this\n", - "example, toluene will be reacted with hydrogen gas at high temperatures\n", - " to form benzene via the following reaction:\n", - "\n", - "**C6H5CH3 + H2 → C6H6 + CH4**\n", - "\n", - "\n", - "This reaction is often accompanied by an equilibrium side reaction\n", - "which forms diphenyl, which we will neglect for this example.\n", - "\n", - "This example is based on the 1967 AIChE Student Contest problem as\n", - "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", - "McGraw-Hill.\n", - "\n", - "Users may refer to the prior examples linked at the top of this notebook for detailed process descriptions of the two HDA configurations. As before, the properties required for this module are defined in\n", - "\n", - "- `hda_ideal_VLE.py`\n", - "- `idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE`\n", - "- `hda_reaction.py`\n", - "\n", - "Additionally, we will be importing externally-defined flowsheets for the two HDA configurations from\n", - "\n", - "- `hda_flowsheets_for_costing_notebook.py`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Import and run HDA Flowsheets\n", - "First, we will generate solved flowsheets for each HDA model. The external scripts build and set inputs for the flowsheets, initialize unit models and streams, and solve the flowsheets before returning the model objects. Note that the HDA flowsheets contain all unit models and stream connections, and no costing equations." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The flowsheet utilizes the Wegstein method to iteratively solve circular dependencies such as recycle streams, and is intended to approach a feasible solution. As such, the calls below will fail to converge after 3 iterations and pass to IPOPT to obtain an optimal solution as expected:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Source file for prebuilt flowsheets\n", - "from hda_flowsheets_for_costing_notebook import hda_with_flash\n", - "\n", - "# Build hda model with second flash unit and return model object\n", - "m = hda_with_flash(tee=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## IDAES Process Costing Framework\n", - "IDAES provides a library of capital costing correlations based on those in the following source:\n", - "\n", - "*Process and Product Design Principles: Synthesis, Analysis, and Evaluation*. Seider, Seader, Lewin, Windagdo, 3rd Ed. John Wiley and Sons Chapter 22. Cost Accounting and Capital Cost Estimation 22.2 Cost Indexes and Capital Investment.\n", - "\n", - "Currently, IDAES supports calculation of capital costing for a wide array of unit operations, vesseel sizing and material properties, and specific unit options such as column tray types and heat exchanger configurations. Users may find further information on specific costing methods and options in the IDAES Process Costing Framework documentation (link pending).\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add Operating Cost Equations\n", - "Before adding capital costing blocks, we will add operating cost equations taken from the basic [HDA with Flash](../tut/hda_flowsheet_solution_usr.ipynb) and the HDA with Distillation examples. The examples assume constant cooling and heating coefficients over an annual cost basis. The IDAES Generic Costing Framework does not currently support variable cost calculations." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Required imports\n", - "from pyomo.environ import Expression\n", - "\n", - "# Operating costs for HDA with second flash (model m)\n", - "m.fs.cooling_cost = Expression(\n", - " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", - ")\n", - "m.fs.heating_cost = Expression(\n", - " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", - ")\n", - "m.fs.operating_cost = Expression(\n", - " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add Capital Costing\n", - "Below, we will add add capital costing blocks to the imported flowsheets and evaluate the economic impact of replacing the second Flash with a Distillation column. First, let's import and define the main flowsheet costing block:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Import costing methods - classes, heaters, vessels, compressors, columns\n", - "from idaes.models.costing.SSLW import (\n", - " SSLWCosting,\n", - " SSLWCostingData,\n", - ")\n", - "from idaes.core import UnitModelCostingBlock\n", - "\n", - "# Costing block\n", - "m.fs.costing = SSLWCosting()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will build the relevant costing blocks for the equipment we wish to cost. Note how the costing block, methods and flags are passed as arguments in the costing block call itself. Each unit model will have a single costing block, but each flowsheet model (m and n) will also have a single costing block for flowsheet-level properties.\n", - "\n", - "Users should note that IDAES costing methods support a wide array of heating sources (e.g. fired, steam boiler, hot water) and do not support direct capital costing of coolers. If users wish to cost Heater units acting as coolers, it is necessary to cost a \"dummy\" [0D shell and tube exchanger](https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/heat_exchanger.html) with appropriate aliased hot stream properties and proper cooling water properties. This is not demonstrated here, as the HDA examples take advantage of Flash and Condenser operations to recover liquid product.\n", - "\n", - "Capital costing is independent of unit model connections, and building cost equations may be done piecewise in this fashion. Default options are passed explicitly to demonstrate proper syntax and usage. Now that all required properties are defined, let's cost our models connecting costing blocks, methods and unit models in each flowsheet." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Flexibility of Costing Block Definitions\n", - "IDAES supports many ways to define batches of costing blocks, and several are shown in the example. Users may employ whichever method fits their modeling needs for explicit or concise code. In the code below, note how the unit model itself is never passed to the costing method; when the full model is executed, the costing block will automatically connect its parent block with child equation blocks.\n", - "\n", - "`Compressor` unit models with isothermal or adiabatic thermodynamics are too simple to cost and are therefore excluded from the economic analysis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's define costing for the heater unit:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.costing.SSLW import (\n", - " HeaterMaterial,\n", - " HeaterSource,\n", - ")\n", - "\n", - "# Costing for heater - m.fs.H101\n", - "m.fs.H101.costing = UnitModelCostingBlock(\n", - " flowsheet_costing_block=m.fs.costing,\n", - " costing_method=SSLWCostingData.cost_fired_heater,\n", - " costing_method_arguments={\n", - " \"material_type\": HeaterMaterial.CarbonSteel,\n", - " \"heat_source\": HeaterSource.Fuel,\n", - " },\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The costing module provides a `unit_mapping` dictionary linking generic unit model classes with recommended costing methods. In this example, StoichiometricReactor and Flash vessels utilize different vessel costing methods with similar arguments. The diameter and length attributes need to exist in order to cost vessel sizing and material requirements, and we add them if they don't exist already. The `unit_mapping` method provides an opportunity to automatically select the correct vessel orientation (vertical or horizontal) based on the unit type; passing a `StoichiometricReactor` or `PFR` class object will call the `cost_horizontal_vessel` method, while passing a `Flash` or `CSTR` class object will call the `cost_vertical_vessel` method.\n", - "\n", - "All vessels are assigned costing succinctly via a loop below - users may define each block individually if desired:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.costing.SSLW import (\n", - " VesselMaterial,\n", - " TrayType,\n", - " TrayMaterial,\n", - ")\n", - "\n", - "from idaes.core.util.constants import Constants\n", - "from pyomo.environ import Var, Constraint, units as pyunits, Param, value\n", - "from idaes.models.unit_models import StoichiometricReactor, Flash\n", - "\n", - "# Map unit models to unit classes\n", - "# Will pass to unit_mapping which calls costing methods based on unit class\n", - "unit_class_mapping = {\n", - " m.fs.R101: StoichiometricReactor,\n", - " m.fs.F101: Flash,\n", - " m.fs.F102: Flash,\n", - "}\n", - "\n", - "# Costing for vessels - m.fs.R101, m.fs.F101, m.fs.F102\n", - "\n", - "# Loop over units\n", - "for unit in [m.fs.R101, m.fs.F101, m.fs.F102]:\n", - " # Get correct unit class for unit model\n", - " unit_class = unit_class_mapping[unit]\n", - "\n", - " # Add dimension variables and constraint if they don't exist\n", - " if not hasattr(unit, \"diameter\"):\n", - " unit.diameter = Var(initialize=1, units=pyunits.m)\n", - " if not hasattr(unit, \"length\"):\n", - " unit.length = Var(initialize=1, units=pyunits.m)\n", - " if hasattr(unit, \"volume\"): # if volume exists, set diameter from volume\n", - " unit.volume_eq = Constraint(\n", - " expr=unit.volume[0] == unit.length * unit.diameter**2 * 0.25 * Constants.pi\n", - " )\n", - " else: # fix diameter directly\n", - " unit.diameter.fix(0.2214 * pyunits.m)\n", - " # Either way, fix L/D to calculate L from D\n", - " unit.L_over_D = Constraint(expr=unit.length == 3 * unit.diameter)\n", - "\n", - " # Define vessel costing\n", - " unit.costing = UnitModelCostingBlock(\n", - " flowsheet_costing_block=unit.parent_block().costing, # e.g. m.fs.R101.costing\n", - " costing_method=SSLWCostingData.unit_mapping[\n", - " unit_class\n", - " ], # e.g. cost_vertical_vessel()\n", - " costing_method_arguments={\n", - " \"material_type\": VesselMaterial.CarbonSteel,\n", - " \"shell_thickness\": 1.25 * pyunits.inch,\n", - " },\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Solve Flowsheet Costing Blocks\n", - "Now, we may solve the full flowsheet for all costing blocks:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Eefine solver\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", - "\n", - "# Check that the degrees of freedom is zero\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "\n", - "assert degrees_of_freedom(m) == 0" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Check physical units consistency, solve and check solver status\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.util.check_units import assert_units_consistent\n", - "\n", - "assert_units_consistent(m)\n", - "results = solver.solve(m, tee=True, symbolic_solver_labels=True)\n", - "assert results.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For comparison, we will call and build the HDA flowsheet replacing the second `Flash` with a `TrayColumn` distillation unit model. The flowsheet costing occurs in the external script `hda_flowsheets_for_costing_notebook.py` and is not shown here:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "from pyomo.common.log import LoggingIntercept\n", - "import logging\n", - "from io import StringIO\n", - "\n", - "stream = StringIO()\n", - "with LoggingIntercept(stream, \"idaes\", logging.WARNING):\n", - " # Source file for prebuilt flowsheets\n", - " from hda_flowsheets_for_costing_notebook import hda_with_distillation\n", - "\n", - " # Build hda model with distillation column and return model object\n", - " n = hda_with_distillation(tee=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results Comparison and Visualization\n", - "For the two flowsheets above, let's sum the total operating and capital costs of each scenario. We will display overall process economics results and compare the two flowsheets:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports and data gathering\n", - "from matplotlib import pyplot as plt\n", - "\n", - "plt.style.use(\"dark_background\") # if using browser in dark mode, uncomment this line\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "# Automatically get units that we costed - this will exclude C101 for both flowsheets\n", - "\n", - "two_flash_unitlist = [\n", - " getattr(m.fs, unit) for unit in dir(m.fs) if hasattr(getattr(m.fs, unit), \"costing\")\n", - "]\n", - "distillation_unitlist = [\n", - " getattr(n.fs, unit) for unit in dir(n.fs) if hasattr(getattr(n.fs, unit), \"costing\")\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Compare equipment purchase costs (actual capital costs)\n", - "\n", - "two_flash_capcost = {\n", - " unit.name: value(unit.costing.capital_cost / 1e3) for unit in two_flash_unitlist\n", - "}\n", - "distillation_capcost = {\n", - " unit.name: value(unit.costing.capital_cost / 1e3) for unit in distillation_unitlist\n", - "}\n", - "\n", - "two_flash_capdf = pd.DataFrame(\n", - " list(two_flash_capcost.items()), columns=[\"Equipment\", \"Two Flash\"]\n", - ").set_index(\"Equipment\")\n", - "distillation_capdf = pd.DataFrame(\n", - " list(distillation_capcost.items()), columns=[\"Equipment\", \"Distillation\"]\n", - ").set_index(\"Equipment\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "capcosts = two_flash_capdf.add(distillation_capdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "# Sort according to an easier order to view\n", - "capcosts = capcosts[[\"fs.H101\", \"fs.R101\", \"fs.F101\", \"fs.F102\", \"fs.D101\", \"fs.H102\"]]\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(capcosts) # view dataframe before plotting\n", - "\n", - "capplot = capcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Total Capital Costs\", ylabel=\"$1000\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Compare operating costs (per year)\n", - "\n", - "two_flash_opcost = {\n", - " \"cooling\": value(3600 * 24 * 365 * m.fs.cooling_cost / 1e3),\n", - " \"heating\": value(3600 * 24 * 365 * m.fs.heating_cost / 1e3),\n", - "}\n", - "distillation_opcost = {\n", - " \"cooling\": value(3600 * 24 * 365 * n.fs.cooling_cost / 1e3),\n", - " \"heating\": value(3600 * 24 * 365 * n.fs.heating_cost / 1e3),\n", - "}\n", - "\n", - "two_flash_opdf = pd.DataFrame(\n", - " list(two_flash_opcost.items()), columns=[\"Utilities\", \"Two Flash\"]\n", - ").set_index(\"Utilities\")\n", - "distillation_opdf = pd.DataFrame(\n", - " list(distillation_opcost.items()), columns=[\"Utilities\", \"Distillation\"]\n", - ").set_index(\"Utilities\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "opcosts = two_flash_opdf.add(distillation_opdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(opcosts) # view dataframe before plotting\n", - "\n", - "opplot = opcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Operating Costs\", ylabel=\"$1000/year\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Compare total costs (capital costs and operating costs)\n", - "\n", - "two_flash_totcost = {\n", - " \"capital\": sum(two_flash_capcost[idx] for idx in two_flash_capcost),\n", - " \"operating\": value(m.fs.operating_cost) / 1e3,\n", - "}\n", - "distillation_totcost = {\n", - " \"capital\": sum(distillation_capcost[idx] for idx in distillation_capcost),\n", - " \"operating\": value(n.fs.operating_cost) / 1e3,\n", - "}\n", - "\n", - "two_flash_totdf = pd.DataFrame(\n", - " list(two_flash_totcost.items()), columns=[\"Costs\", \"Two Flash\"]\n", - ").set_index(\"Costs\")\n", - "distillation_totdf = pd.DataFrame(\n", - " list(distillation_totcost.items()), columns=[\"Costs\", \"Distillation\"]\n", - ").set_index(\"Costs\")\n", - "\n", - "# Add dataframes, merge same indices, replace NaNs with 0s, and transpose\n", - "totcosts = two_flash_totdf.add(distillation_totdf, fill_value=0).fillna(0).transpose()\n", - "\n", - "print(\"Costs in $1000:\")\n", - "display(totcosts) # view dataframe before plotting\n", - "\n", - "totplot = totcosts.plot(\n", - " kind=\"bar\", stacked=True, title=\"HDA Total Plant Cost (TPC)\", ylabel=\"$1000/year\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's compare the total costs on a production basis. This will account for the greater efficiency provided by the distillation column relative to the less-expensive second flash unit:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "two_flash_cost = value(1e3 * sum(two_flash_totcost[idx] for idx in two_flash_totcost))\n", - "two_flash_prod = value(\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] * 365 * 24 * 3600\n", - ")\n", - "distillation_cost = value(\n", - " 1e3 * sum(distillation_totcost[idx] for idx in distillation_totcost)\n", - ")\n", - "distillation_prod = value(n.fs.D101.condenser.distillate.flow_mol[0] * 365 * 24 * 3600)\n", - "\n", - "print(\n", - " f\"Two flash case over one year: ${two_flash_cost/1e3:0.0f}K / {two_flash_prod/1e3:0.0f} kmol benzene = ${two_flash_cost/(two_flash_prod/1e3):0.2f} per kmol benzene produced\"\n", - ")\n", - "print(\n", - " f\"Distillation case over one year: ${distillation_cost/1e3:0.0f}K / {distillation_prod/1e3:0.0f} kmol benzene = ${distillation_cost/(distillation_prod/1e3):0.2f} per kmol benzene produced\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Summary\n", - "In this example, IDAES Process Costing Framework methods were applied to two HDA flowsheets for capital cost estimation. The costing blocks calls showcased multiple methods to define unit costing, demonstrating the flexibility and best practice of the costing framework. In the basic examples, the two-flash HDA did not include costing and the distillation HDA estimated a reactor capital cost comprising 3.3% of the total plant cost (TPC). With more rigorous costing, IDAES obtained total capital costs of 8.5% TPC (two flash HDA) and 9.6% (distillation HDA) and better modeled the impact of equipment cost on process economics. As printed above, the IDAES Process Costing Framework confirmed that replacing the second flash drum with a distillation column results in increased equipment costs, increased production and decreased cost per unit product." - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.12" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis.ipynb b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis.ipynb index 20080315..503fe925 100644 --- a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis.ipynb @@ -2,16 +2,18 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "metadata": { - "tags": [ - "header", - "hide-cell" - ], "ExecuteTime": { "end_time": "2026-02-20T21:01:04.629603300Z", "start_time": "2026-02-20T21:01:04.619279Z" - } + }, + "tags": [ + "header", + "hide-cell" + ] }, + "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -25,9 +27,7 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -93,17 +93,13 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2026-02-20T21:01:04.649464300Z", "start_time": "2026-02-20T21:01:04.632133500Z" } }, - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet.png\")" - ], "outputs": [ { "data": { @@ -117,7 +113,11 @@ "output_type": "execute_result" } ], - "execution_count": 2 + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet.png\")" + ] }, { "cell_type": "markdown", @@ -136,12 +136,14 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2026-02-20T21:01:07.389407500Z", "start_time": "2026-02-20T21:01:04.652988700Z" } }, + "outputs": [], "source": [ "import pytest\n", "import os\n", @@ -205,9 +207,7 @@ " add_costing,\n", " report,\n", ")" - ], - "outputs": [], - "execution_count": 3 + ] }, { "cell_type": "markdown", @@ -219,20 +219,20 @@ }, { "cell_type": "code", + "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2026-02-20T21:01:07.399593900Z", "start_time": "2026-02-20T21:01:07.390910200Z" } }, + "outputs": [], "source": [ "# Set solver options\n", "solver = get_solver() # IPOPT\n", "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", "solver.options = optarg" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -249,27 +249,13 @@ }, { "cell_type": "code", + "execution_count": 5, "metadata": { - "scrolled": false, "ExecuteTime": { "end_time": "2026-02-20T21:01:09.234663Z", "start_time": "2026-02-20T21:01:07.401096600Z" } }, - "source": [ - "# Build and solve flowsheet\n", - "m = ConcreteModel()\n", - "build_model(m) # build flowsheet by adding unit models and property packages\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "\n", - "results = solver.solve(m, tee=True) # initial square problem solve" - ], "outputs": [ { "name": "stdout", @@ -287,121 +273,121 @@ "DOF after streams specified: 9\n", "DOF after units specified: 0\n", "\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.H2.properties: Starting initialization\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.H2: Initialization Complete.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.CO.properties: Starting initialization\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.CO: Initialization Complete.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:07 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n", "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", @@ -410,92 +396,92 @@ "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n", "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n", - "2026-02-20 14:01:08 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n", "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n", - "2026-02-20 14:01:09 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n", "DOF before solve: 0\n", "\n", "Solving initial problem...\n", @@ -503,7 +489,7 @@ "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "Ipopt 3.13.2: tol=1e-06\n", + "Ipopt 3.14.20: tol=1e-06\n", "max_iter=100\n", "\n", "\n", @@ -515,7 +501,7 @@ "This version of Ipopt was compiled from source code available at\n", " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", "\n", "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", " for large-scale scientific computation. All technical papers, sales and\n", @@ -525,7 +511,7 @@ " computation. See http://www.hsl.rl.ac.uk.\n", "******************************************************************************\n", "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 955\n", "Number of nonzeros in inequality constraint Jacobian.: 0\n", @@ -545,16 +531,17 @@ " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", " 1 0.0000000e+00 2.79e+02 2.77e+00 -1.0 1.00e-02 - 9.90e-01 9.90e-01h 1\n", " 2 0.0000000e+00 2.77e+00 1.21e+00 -1.0 1.00e-04 - 9.90e-01 9.90e-01h 1\n", - " 3 0.0000000e+00 6.98e-10 1.00e+03 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 9.31e-10 0.00e+00 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", "\n", "Number of Iterations....: 3\n", "\n", " (scaled) (unscaled)\n", "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Constraint violation....: 1.1368683772161603e-13 6.9849193096160889e-10\n", + "Constraint violation....: 1.1368683772161603e-13 9.3132257461547852e-10\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 1.1368683772161603e-13 6.9849193096160889e-10\n", + "Overall NLP error.......: 1.1368683772161603e-13 9.3132257461547852e-10\n", "\n", "\n", "Number of objective function evaluations = 4\n", @@ -564,32 +551,44 @@ "Number of equality constraint Jacobian evaluations = 4\n", "Number of inequality constraint Jacobian evaluations = 0\n", "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.005\n", - "Total CPU secs in NLP function evaluations = 0.000\n", + "Total seconds in IPOPT = 0.003\n", "\n", "EXIT: Optimal Solution Found.\n" ] } ], - "execution_count": 5 + "source": [ + "# Build and solve flowsheet\n", + "m = ConcreteModel()\n", + "build_model(m) # build flowsheet by adding unit models and property packages\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "\n", + "results = solver.solve(m, tee=True) # initial square problem solve" + ] }, { "cell_type": "code", + "execution_count": 6, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-20T21:01:09.241076500Z", "start_time": "2026-02-20T21:01:09.235965Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# check optimal termination\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -601,22 +600,13 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { - "scrolled": false, "ExecuteTime": { "end_time": "2026-02-20T21:01:09.373826200Z", "start_time": "2026-02-20T21:01:09.242152800Z" } }, - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "print(\"Solving with costing...\")\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ], "outputs": [ { "name": "stdout", @@ -628,7 +618,7 @@ "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "Ipopt 3.13.2: tol=1e-06\n", + "Ipopt 3.14.20: tol=1e-06\n", "max_iter=100\n", "\n", "\n", @@ -640,7 +630,7 @@ "This version of Ipopt was compiled from source code available at\n", " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", "\n", "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", " for large-scale scientific computation. All technical papers, sales and\n", @@ -650,7 +640,7 @@ " computation. See http://www.hsl.rl.ac.uk.\n", "******************************************************************************\n", "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 971\n", "Number of nonzeros in inequality constraint Jacobian.: 0\n", @@ -671,33 +661,34 @@ " 1 -2.9068962e+07 5.76e+04 6.45e+01 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", " 2 -2.9074767e+07 5.71e+02 9.98e+00 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", " 3 -2.9074825e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9074825e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9074825e+07 1.63e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9074825e+07 1.16e-09 9.87e-08 -1.0 2.66e-08 - 9.90e-01 1.00e+00h 1\n", "\n", - "Number of Iterations....: 4\n", + "Number of Iterations....: 5\n", "\n", " (scaled) (unscaled)\n", - "Objective...............: -4.4948186430824137e+01 -2.9074824816033222e+07\n", - "Dual infeasibility......: 3.6708958239217049e-07 2.3745263485255724e-01\n", - "Constraint violation....: 4.5474735088646412e-12 1.0477378964424133e-09\n", + "Objective...............: -4.4948186430824109e+01 -2.9074824816033181e+07\n", + "Dual infeasibility......: 9.8709848486689587e-08 6.3850664070387003e-02\n", + "Constraint violation....: 4.5474735088646412e-12 1.1641532182693481e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 2.3745263485255724e-01\n", + "Overall NLP error.......: 9.8709848486689587e-08 6.3850664070387003e-02\n", "\n", "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", + "Number of equality constraint Jacobian evaluations = 6\n", "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.005\n", - "Total CPU secs in NLP function evaluations = 0.001\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.006\n", "\n", "EXIT: Optimal Solution Found.\n", "Initial solution process results:\n", "\n", "\n", - "Extent of reaction: 237.6004779\n", + "Extent of reaction: 237.60047790000004\n", "Stoichiometry of each component normalized by the extent:\n", "CH4 : 0.0\n", "H2 : -2.0\n", @@ -706,24 +697,24 @@ "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", "\n", "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.21917830318435\n", - "Duty from Reaction (MW)): 21.536107316856\n", - "Turbine work (MW): -0.9593346445867499\n", - "Mixer outlet temperature (C)): 20.051714213753257\n", - "Compressor outlet temperature (C)): 20.051714213753257\n", + "Reactor duty (MW): -45.21917830318437\n", + "Duty from Reaction (MW)): 21.536107316856004\n", + "Turbine work (MW): -0.9593346445867349\n", + "Mixer outlet temperature (C)): 20.0517142137536\n", + "Compressor outlet temperature (C)): 20.05171421375354\n", "Compressor outlet pressure (Pa)): 5100000.0\n", "Heater outlet temperature (C)): 215.0\n", "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.8781524424324\n", + "Turbine outlet temperature (C)): 192.87815244243325\n", "Turbine outlet pressure (Pa)): 3100000.0\n", "Cooler outlet temperature (C)): 134.0\n", "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 60.004430129216836\n", - "annualized capital cost ($/year) = 219790.5044704343\n", - "operating cost ($/year) = 380701687.4964806\n", - "sales ($/year) = 64685201172.198135\n", + "Methanol recovery(%): 60.00443012921678\n", + "annualized capital cost ($/year) = 219790.50447043462\n", + "operating cost ($/year) = 380701687.4964803\n", + "sales ($/year) = 64685201172.198105\n", "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29074824.816033214\n", + "revenue (1000$/year)= 29074824.816033185\n", "\n", "\n", "====================================================================================\n", @@ -784,25 +775,33 @@ ] } ], - "execution_count": 7 + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "print(\"Solving with costing...\")\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { "cell_type": "code", + "execution_count": 8, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-20T21:01:09.381154800Z", "start_time": "2026-02-20T21:01:09.375269800Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# check optimal termination\n", "assert results2.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -813,60 +812,13 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { - "scrolled": false, "ExecuteTime": { "end_time": "2026-02-20T21:01:09.500156800Z", "start_time": "2026-02-20T21:01:09.382424800Z" } }, - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "opt_res = solver.solve(m, tee=True)\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ], "outputs": [ { "name": "stdout", @@ -878,7 +830,7 @@ "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "Ipopt 3.13.2: tol=1e-06\n", + "Ipopt 3.14.20: tol=1e-06\n", "max_iter=100\n", "\n", "\n", @@ -890,7 +842,7 @@ "This version of Ipopt was compiled from source code available at\n", " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", "\n", "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", " for large-scale scientific computation. All technical papers, sales and\n", @@ -900,7 +852,7 @@ " computation. See http://www.hsl.rl.ac.uk.\n", "******************************************************************************\n", "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 975\n", "Number of nonzeros in inequality constraint Jacobian.: 8\n", @@ -928,56 +880,75 @@ " 8 -2.8537637e+07 2.15e+04 6.77e+06 -1.0 1.30e+06 - 4.68e-01 1.17e-04h 1\n", " 9 -2.8910081e+07 8.51e+04 2.07e+06 -1.0 1.31e+06 - 4.38e-01 9.05e-01h 1\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -2.8916017e+07 7.81e+04 1.11e+08 -1.0 9.39e+04 -4.0 3.56e-03 8.26e-02h 1\n", - " 11 -2.8916050e+07 7.80e+04 1.11e+08 -1.0 8.73e+04 -4.5 9.12e-02 9.05e-04h 1\n", - " 12 -2.8951501e+07 1.29e+04 3.00e+07 -1.0 8.73e+04 - 1.37e-02 9.90e-01h 1\n", - " 13 -2.8964697e+07 3.52e+03 9.82e+06 -1.0 2.95e+04 - 8.80e-01 9.92e-01h 1\n", - " 14 -2.9150638e+07 4.25e+00 6.53e+07 -1.0 1.59e+04 - 9.88e-01 1.00e+00h 1\n", - " 15 -3.2694771e+07 3.47e+03 1.38e+08 -1.0 3.00e+05 - 3.58e-01 1.00e+00f 1\n", - " 16 -3.9657884e+07 3.74e+02 4.98e+06 -1.0 6.48e+05 - 9.11e-01 1.00e+00F 1\n", - " 17 -5.8700677e+07 2.03e+04 1.12e+06 -1.0 2.00e+06 - 2.65e-01 1.00e+00F 1\n", - " 18 -7.8085174e+07 1.40e+05 4.14e+05 -1.0 4.34e+06 - 7.55e-01 7.57e-01f 1\n", - " 19 -7.9333792e+07 1.60e+05 2.63e+05 -1.0 3.52e+06 - 9.63e-01 3.03e-01h 1\n", + " 10 -2.8914165e+07 7.59e+04 7.45e+06 -1.0 9.51e+04 - 9.00e-01 1.08e-01h 1\n", + " 11 -2.8947367e+07 1.17e+03 1.82e+05 -1.0 8.76e+04 - 9.09e-01 9.90e-01h 1\n", + " 12 -2.8953051e+07 1.08e+01 5.44e+06 -1.0 1.43e+03 -4.0 3.59e-02 9.92e-01h 1\n", + " 13 -2.8953104e+07 4.13e-04 1.09e+05 -1.0 2.11e+01 -4.5 9.90e-01 1.00e+00h 1\n", + " 14 -2.8953015e+07 2.97e-05 8.41e+04 -1.0 3.36e+01 -5.0 9.90e-01 1.00e+00f 1\n", + " 15 -2.8952945e+07 9.83e-05 7.75e+02 -1.0 6.25e+01 -5.4 9.91e-01 1.00e+00f 1\n", + " 16 -2.8952999e+07 1.24e-05 4.07e+00 -1.7 2.92e+01 -5.9 1.00e+00 1.00e+00f 1\n", + " 17 -2.8953295e+07 1.59e-05 3.08e+04 -3.8 1.68e+01 -6.4 9.84e-01 1.00e+00f 1\n", + " 18 -6.7235329e+07 3.98e+05 3.08e+04 -3.8 3.24e+06 - 6.31e-04 1.00e+00f 1\n", + " 19 -6.7161096e+07 3.96e+05 3.08e+04 -3.8 3.97e+05 -6.9 4.51e-04 6.00e-03h 1\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -7.7164009e+07 3.20e+03 7.59e+03 -1.0 4.56e+05 - 9.91e-01 1.00e+00h 1\n", - " 21 -7.7545831e+07 3.83e+03 5.53e+01 -1.0 2.78e+05 - 1.00e+00 1.00e+00h 1\n", - " 22 -7.7683360e+07 9.76e+02 2.23e+06 -2.5 6.32e+04 - 1.00e+00 7.70e-01h 1\n", - " 23 -7.7696221e+07 8.35e+00 1.48e+02 -2.5 6.87e+04 - 1.00e+00 1.00e+00h 1\n", - " 24 -7.7696183e+07 8.31e-03 4.61e-03 -2.5 2.13e+03 - 1.00e+00 1.00e+00h 1\n", - " 25 -7.7699949e+07 5.36e+00 1.27e+04 -5.7 7.60e+04 - 9.49e-01 9.94e-01f 1\n", - " 26 -7.7700458e+07 8.84e+01 1.03e+03 -5.7 3.66e+05 - 9.25e-01 9.72e-01h 1\n", - " 27 -7.7700530e+07 1.74e+01 1.01e+01 -5.7 6.59e+04 - 1.00e+00 8.03e-01h 1\n", - " 28 -7.7700531e+07 2.07e-04 4.22e-06 -5.7 1.25e+03 - 1.00e+00 1.00e+00h 1\n", - " 29 -7.7700536e+07 9.48e-04 1.29e-01 -8.6 1.69e+03 - 1.00e+00 9.99e-01h 1\n", + " 20r-6.7161096e+07 3.96e+05 1.00e+03 1.1 0.00e+00 -7.3 0.00e+00 3.70e-07R 5\n", + " 21r-6.0126088e+07 1.13e+05 9.98e+02 1.1 9.47e+08 - 7.54e-04 8.89e-04f 1\n", + " 22 -5.8571015e+07 9.76e+04 1.26e+02 -3.8 1.33e+06 - 2.10e-01 1.37e-01h 1\n", + " 23 -5.8570701e+07 9.76e+04 4.63e+04 -3.8 1.17e+06 - 5.53e-01 3.23e-05h 1\n", + " 24 -5.8606170e+07 8.79e+04 1.84e+05 -3.8 2.62e+06 - 5.56e-03 9.99e-02h 1\n", + " 25 -5.8612488e+07 8.60e+04 7.19e+05 -3.8 2.49e+06 - 2.94e-01 2.08e-02h 1\n", + " 26 -5.8740061e+07 4.93e+04 1.28e+05 -3.8 2.43e+06 - 1.96e-01 4.35e-01h 1\n", + " 27 -5.8740292e+07 4.91e+04 3.28e+07 -3.8 9.94e+05 - 6.54e-01 4.63e-03h 1\n", + " 28 -5.8788497e+07 5.30e+03 1.02e+07 -3.8 9.26e+05 - 8.88e-01 1.00e+00h 1\n", + " 29 -5.8643006e+07 5.29e+03 1.65e+07 -3.8 2.35e+07 - 9.21e-04 1.55e-03h 7\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.7700536e+07 6.52e-09 5.32e-11 -8.6 1.52e+00 - 1.00e+00 1.00e+00f 1\n", - " 31 -7.7700536e+07 8.38e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 31\n", + " 30 -5.7470132e+07 2.03e+02 1.15e+09 -3.8 2.85e+05 - 9.22e-06 1.00e+00h 1\n", + " 31 -5.7582403e+07 9.77e+00 1.14e+08 -3.8 1.63e+04 - 9.98e-01 1.00e+00h 1\n", + " 32 -7.8527164e+07 1.13e+05 8.45e+06 -3.8 4.35e+06 - 4.64e-01 9.37e-01f 1\n", + " 33 -7.8529326e+07 1.13e+05 8.45e+06 -3.8 5.31e+06 - 7.75e-01 1.16e-04h 1\n", + " 34 -7.9550162e+07 1.33e+05 6.60e+06 -3.8 4.19e+06 - 8.67e-01 2.18e-01h 1\n", + " 35 -7.9541163e+07 1.33e+05 6.57e+06 -3.8 3.58e+05 - 1.65e-03 4.97e-03h 1\n", + " 36 -7.9533059e+07 1.32e+05 6.54e+06 -3.8 1.15e+05 -7.8 1.26e-06 4.40e-03h 1\n", + " 37 -7.9485981e+07 1.29e+05 6.39e+06 -3.8 6.04e+04 -8.3 9.51e-01 2.34e-02h 1\n", + " 38 -7.8379026e+07 4.89e+04 2.42e+06 -3.8 1.52e+05 - 6.47e-01 6.21e-01h 1\n", + " 39 -7.8367473e+07 4.80e+04 2.38e+06 -3.8 5.52e+04 -8.8 3.60e-03 1.70e-02h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 -7.7618174e+07 1.40e+02 3.78e+03 -3.8 3.11e+04 -9.2 1.00e+00 1.00e+00h 1\n", + " 41 -7.7621799e+07 9.06e-01 7.63e-02 -3.8 4.67e+03 - 1.00e+00 1.00e+00h 1\n", + " 42 -7.7699327e+07 1.63e+02 9.22e-03 -3.8 6.11e+04 - 1.00e+00 1.00e+00f 1\n", + " 43 -7.7700167e+07 4.77e-02 2.09e-06 -3.8 1.01e+04 - 1.00e+00 1.00e+00h 1\n", + " 44 -7.7700500e+07 3.88e+00 3.43e+02 -5.7 9.57e+04 - 9.77e-01 1.00e+00h 1\n", + " 45 -7.7700531e+07 4.16e-01 1.40e-03 -5.7 2.26e+04 - 1.00e+00 9.06e-01h 1\n", + " 46 -7.7700531e+07 5.03e-04 3.89e-08 -5.7 9.81e+02 - 1.00e+00 1.00e+00f 1\n", + " 47 -7.7700536e+07 9.48e-04 2.13e-01 -8.6 1.62e+03 - 1.00e+00 9.99e-01h 1\n", + " 48 -7.7700536e+07 5.82e-09 1.08e-10 -8.6 1.88e+00 - 1.00e+00 1.00e+00f 1\n", + " 49 -7.7700536e+07 9.31e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 49\n", "\n", " (scaled) (unscaled)\n", - "Objective...............: -1.2012103932708916e+02 -7.7700535938862860e+07\n", - "Dual infeasibility......: 6.9713197782916848e-11 4.5094122229452131e-05\n", - "Constraint violation....: 9.4587448984384537e-11 8.3819031715393066e-09\n", - "Complementarity.........: 1.4074777632989367e-11 9.1042982264387185e-06\n", - "Overall NLP error.......: 9.4587448984384537e-11 4.5094122229452131e-05\n", - "\n", - "\n", - "Number of objective function evaluations = 34\n", - "Number of objective gradient evaluations = 32\n", - "Number of equality constraint evaluations = 34\n", - "Number of inequality constraint evaluations = 34\n", - "Number of equality constraint Jacobian evaluations = 32\n", - "Number of inequality constraint Jacobian evaluations = 32\n", - "Number of Lagrangian Hessian evaluations = 31\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.026\n", - "Total CPU secs in NLP function evaluations = 0.003\n", + "Objective...............: -1.2012103932708935e+02 -7.7700535938862920e+07\n", + "Dual infeasibility......: 6.9703019509761989e-11 4.5087538392986020e-05\n", + "Constraint violation....: 1.0186340659856796e-10 9.3132257461547852e-09\n", + "Variable bound violation: 5.1274423640279565e-06 5.1274423640279565e-06\n", + "Complementarity.........: 1.4074777602003514e-11 9.1042982063954507e-06\n", + "Overall NLP error.......: 1.0186340659856796e-10 4.5087538392986020e-05\n", + "\n", + "\n", + "Number of objective function evaluations = 63\n", + "Number of objective gradient evaluations = 50\n", + "Number of equality constraint evaluations = 63\n", + "Number of inequality constraint evaluations = 63\n", + "Number of equality constraint Jacobian evaluations = 51\n", + "Number of inequality constraint Jacobian evaluations = 51\n", + "Number of Lagrangian Hessian evaluations = 49\n", + "Total seconds in IPOPT = 0.048\n", "\n", "EXIT: Optimal Solution Found.\n", "Optimal solution process results:\n", "\n", "\n", - "Extent of reaction: 269.2805447879921\n", + "Extent of reaction: 269.280544787992\n", "Stoichiometry of each component normalized by the extent:\n", "CH4 : 0.0\n", "H2 : -2.0\n", @@ -986,24 +957,24 @@ "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", "\n", "Reaction conversion: 0.8500000099999546\n", - "Reactor duty (MW): -51.363573577545786\n", - "Duty from Reaction (MW)): 24.407588579583603\n", - "Turbine work (MW): -1.9904899177794815\n", - "Mixer outlet temperature (C)): 20.0517142137536\n", - "Compressor outlet temperature (C)): 20.0517142137536\n", + "Reactor duty (MW): -51.36357357754579\n", + "Duty from Reaction (MW)): 24.407588579583596\n", + "Turbine work (MW): -1.9904899177794853\n", + "Mixer outlet temperature (C)): 20.05171421375337\n", + "Compressor outlet temperature (C)): 20.051714213753485\n", "Compressor outlet pressure (Pa)): 5100000.0\n", "Heater outlet temperature (C)): 215.0\n", "Reactor outlet temperature (C)): 231.85000468716584\n", - "Turbine outlet temperature (C)): 139.85888172675686\n", + "Turbine outlet temperature (C)): 139.85888172675567\n", "Turbine outlet pressure (Pa)): 1427653.3547820917\n", "Cooler outlet temperature (C)): 52.56999709299214\n", "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 92.8035547465754\n", - "annualized capital cost ($/year) = 235547.18924473316\n", - "operating cost ($/year) = 451663512.6847629\n", - "sales ($/year) = 113381889876.90082\n", + "Methanol recovery(%): 92.80355474657543\n", + "annualized capital cost ($/year) = 235547.18924473305\n", + "operating cost ($/year) = 451663512.6847631\n", + "sales ($/year) = 113381889876.90088\n", "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 77700535.93886285\n", + "revenue (1000$/year)= 77700535.9388629\n", "\n", "\n", "====================================================================================\n", @@ -1064,7 +1035,53 @@ ] } ], - "execution_count": 9 + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "opt_res = solver.solve(m, tee=True)\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, { "cell_type": "markdown", @@ -1075,15 +1092,17 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-20T21:01:09.508319Z", "start_time": "2026-02-20T21:01:09.501157500Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# testing model results\n", "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", @@ -1095,9 +1114,7 @@ "assert value(m.fs.T101.work_isentropic[0]) / 1e6 == pytest.approx(-1.9905, rel=1e-5)\n", "assert value(m.fs.F101.recovery * 100) == pytest.approx(92.8036, rel=1e-5)\n", "assert value(m.fs.objective) / 1e6 == pytest.approx(77.7005, rel=1e-5)" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -1128,17 +1145,13 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2026-02-20T21:01:09.517374100Z", "start_time": "2026-02-20T21:01:09.509320Z" } }, - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet_recycle.png\")" - ], "outputs": [ { "data": { @@ -1152,7 +1165,11 @@ "output_type": "execute_result" } ], - "execution_count": 11 + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet_recycle.png\")" + ] }, { "cell_type": "markdown", @@ -1165,12 +1182,14 @@ }, { "cell_type": "code", + "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2026-02-20T21:01:09.534388600Z", "start_time": "2026-02-20T21:01:09.517374100Z" } }, + "outputs": [], "source": [ "import pytest\n", "import os\n", @@ -1237,9 +1256,7 @@ " add_costing,\n", " report,\n", ")" - ], - "outputs": [], - "execution_count": 12 + ] }, { "cell_type": "markdown", @@ -1251,32 +1268,13 @@ }, { "cell_type": "code", + "execution_count": 13, "metadata": { - "scrolled": false, "ExecuteTime": { "end_time": "2026-02-20T21:01:12.393968500Z", "start_time": "2026-02-20T21:01:09.535877100Z" } }, - "source": [ - "# Build and solve flowsheet\n", - "solver = get_solver() # IPOPT\n", - "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", - "solver.options = optarg\n", - "\n", - "m = ConcreteModel() # create a new model so we may reference 'm' below\n", - "build_model(m) # build flowsheet\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "\n", - "# let the solver determine the tear stream\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "results = solver.solve(m, tee=True)" - ], "outputs": [ { "name": "stdout", @@ -1562,7 +1560,7 @@ "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "Ipopt 3.13.2: tol=1e-06\n", + "Ipopt 3.14.20: tol=1e-06\n", "max_iter=100\n", "\n", "\n", @@ -1574,7 +1572,7 @@ "This version of Ipopt was compiled from source code available at\n", " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", "\n", "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", " for large-scale scientific computation. All technical papers, sales and\n", @@ -1584,7 +1582,7 @@ " computation. See http://www.hsl.rl.ac.uk.\n", "******************************************************************************\n", "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 1211\n", "Number of nonzeros in inequality constraint Jacobian.: 0\n", @@ -1605,51 +1603,70 @@ " 1 0.0000000e+00 2.79e+02 4.22e+03 -1.0 1.96e+03 - 9.90e-01 9.90e-01h 1\n", " 2 0.0000000e+00 2.77e+00 3.86e+03 -1.0 2.03e+01 - 9.90e-01 9.90e-01h 1\n", " 3 0.0000000e+00 7.44e-06 1.01e+03 -1.0 2.01e-01 - 9.90e-01 1.00e+00h 1\n", - "Cannot recompute multipliers for feasibility problem. Error in eq_mult_calculator\n", + " 4 0.0000000e+00 2.10e-09 9.89e+04 -1.0 1.19e-07 - 9.90e-01 1.00e+00h 1\n", + " 5 0.0000000e+00 2.10e-09 0.00e+00 -1.0 2.51e-08 - 9.91e-01 1.00e+00h 1\n", "\n", - "Number of Iterations....: 3\n", + "Number of Iterations....: 5\n", "\n", " (scaled) (unscaled)\n", "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 1.0099088928127792e+05 1.0099088928127792e+05\n", - "Constraint violation....: 2.4014227693119351e-10 7.4444105848670006e-06\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 6.7595993318865371e-14 2.0954757928848267e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 2.4014227693119351e-10 1.0099088928127792e+05\n", + "Overall NLP error.......: 6.7595993318865371e-14 2.0954757928848267e-09\n", "\n", "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", + "Number of equality constraint Jacobian evaluations = 6\n", "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.004\n", - "Total CPU secs in NLP function evaluations = 0.002\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.009\n", "\n", "EXIT: Optimal Solution Found.\n" ] } ], - "execution_count": 13 + "source": [ + "# Build and solve flowsheet\n", + "solver = get_solver() # IPOPT\n", + "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", + "solver.options = optarg\n", + "\n", + "m = ConcreteModel() # create a new model so we may reference 'm' below\n", + "build_model(m) # build flowsheet\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "\n", + "# let the solver determine the tear stream\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "results = solver.solve(m, tee=True)" + ] }, { "cell_type": "code", + "execution_count": 14, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-20T21:01:12.403359500Z", "start_time": "2026-02-20T21:01:12.393968500Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# check optimal termination\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "markdown", @@ -1661,21 +1678,13 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { - "scrolled": false, "ExecuteTime": { "end_time": "2026-02-20T21:01:12.612557100Z", "start_time": "2026-02-20T21:01:12.405029Z" } }, - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ], "outputs": [ { "name": "stdout", @@ -1686,7 +1695,7 @@ "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "Ipopt 3.13.2: tol=1e-06\n", + "Ipopt 3.14.20: tol=1e-06\n", "max_iter=100\n", "\n", "\n", @@ -1698,7 +1707,7 @@ "This version of Ipopt was compiled from source code available at\n", " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", "\n", "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", " for large-scale scientific computation. All technical papers, sales and\n", @@ -1708,7 +1717,7 @@ " computation. See http://www.hsl.rl.ac.uk.\n", "******************************************************************************\n", "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 1227\n", "Number of nonzeros in inequality constraint Jacobian.: 0\n", @@ -1729,33 +1738,40 @@ " 1 -2.9074832e+07 5.76e+04 4.22e+03 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", " 2 -2.9080637e+07 5.71e+02 3.82e+03 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", " 3 -2.9080695e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9080695e+07 9.31e-10 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9080695e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9080695e+07 1.16e-09 9.85e+02 -1.0 2.19e-08 - 9.90e-01 1.00e+00h 1\n", + " 6 -2.9080695e+07 9.31e-10 7.17e+04 -1.7 1.59e-08 - 9.91e-01 1.00e+00h 1\n", + " 7 -2.9080695e+07 9.31e-10 2.00e-07 -1.7 2.11e-08 - 1.00e+00 1.00e+00h 1\n", + " 8 -2.9080695e+07 9.31e-10 1.01e-09 -5.7 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + " 9 -2.9080695e+07 9.31e-10 3.69e-13 -8.6 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -2.9080695e+07 9.31e-10 2.90e-13 -10.9 1.43e-08 - 1.00e+00 1.00e+00h 1\n", "\n", - "Number of Iterations....: 4\n", + "Number of Iterations....: 10\n", "\n", " (scaled) (unscaled)\n", - "Objective...............: -4.4953175283791907e+01 -2.9080695361147854e+07\n", - "Dual infeasibility......: 2.4946824403693549e-06 1.6138370562967401e+00\n", + "Objective...............: -4.4953175283792277e+01 -2.9080695361147840e+07\n", + "Dual infeasibility......: 2.8986503540945592e-13 1.8751682695104163e-07\n", "Constraint violation....: 4.5474735088646412e-12 9.3132257461547852e-10\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 1.6138370562967401e+00\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.4052801174098027e-11 9.0909090922898242e-06\n", + "Overall NLP error.......: 1.4052801174098027e-11 9.0909090922898242e-06\n", "\n", "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", + "Number of objective function evaluations = 11\n", + "Number of objective gradient evaluations = 11\n", + "Number of equality constraint evaluations = 11\n", "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", + "Number of equality constraint Jacobian evaluations = 11\n", "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.005\n", - "Total CPU secs in NLP function evaluations = 0.002\n", + "Number of Lagrangian Hessian evaluations = 10\n", + "Total seconds in IPOPT = 0.017\n", "\n", "EXIT: Optimal Solution Found.\n", "Initial solution process results:\n", "\n", "\n", - "Extent of reaction: 237.6064180604515\n", + "Extent of reaction: 237.60641806045152\n", "Stoichiometry of each component normalized by the extent:\n", "CH4 : 0.0\n", "H2 : -2.0\n", @@ -1764,27 +1780,27 @@ "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", "\n", "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.22029794711382\n", + "Reactor duty (MW): -45.22029794711383\n", "Duty from Reaction (MW)): 21.536645732999325\n", - "Compressor work (MW): -2.5668711294294714e-15\n", - "Turbine work (MW): -0.959378502391431\n", - "Feed Mixer outlet temperature (C)): 20.051714213753144\n", - "Recycle Mixer outlet temperature (C)): 20.056485612776214\n", - "Feed Compressor outlet temperature (C)): 20.0564856127761\n", + "Compressor work (MW): -3.72291430867571e-35\n", + "Turbine work (MW): -0.9593785023914099\n", + "Feed Mixer outlet temperature (C)): 20.0517142137532\n", + "Recycle Mixer outlet temperature (C)): 20.056485612776157\n", + "Feed Compressor outlet temperature (C)): 20.056485612776157\n", "Feed Compressor outlet pressure (Pa)): 5100000.0\n", "Heater outlet temperature (C)): 215.0\n", "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.87840947667888\n", + "Turbine outlet temperature (C)): 192.8784094766802\n", "Turbine outlet pressure (Pa)): 3100000.0\n", "Cooler outlet temperature (C)): 134.0\n", "Flash outlet temperature (C)): 134.0\n", "Purge percentage (amount of vapor vented to exhaust): 99.99 %\n", - "Methanol recovery(%): 60.005984934911716\n", - "annualized capital cost ($/year) = 219794.2325658716\n", - "operating cost ($/year) = 380711692.18369955\n", - "sales ($/year) = 64691081725.72807\n", + "Methanol recovery(%): 60.0059849349117\n", + "annualized capital cost ($/year) = 219794.23256587266\n", + "operating cost ($/year) = 380711692.1836992\n", + "sales ($/year) = 64691081725.72806\n", "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29080695.36114784\n", + "revenue (1000$/year)= 29080695.361147825\n", "\n", "\n", "====================================================================================\n", @@ -1845,25 +1861,32 @@ ] } ], - "execution_count": 15 + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { "cell_type": "code", + "execution_count": 16, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-20T21:01:12.622485200Z", "start_time": "2026-02-20T21:01:12.613467100Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# check optimal termination\n", "assert results2.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 16 + ] }, { "cell_type": "markdown", @@ -1874,82 +1897,13 @@ }, { "cell_type": "code", + "execution_count": 17, "metadata": { - "scrolled": false, "ExecuteTime": { "end_time": "2026-02-20T21:01:13.760944100Z", "start_time": "2026-02-20T21:01:12.626378Z" } }, - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", - "m.fs.S101.split_fraction_lb = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", - ") # min 10% purge\n", - "m.fs.S101.split_fraction_ub = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", - ") # max 50% purge\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "\n", - "# Pass 1: smoothed VLE transition\n", - "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "# Pass 2: restore default smoothness\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ], "outputs": [ { "name": "stdout", @@ -1961,8 +1915,8 @@ "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", "\n", "\n", "******************************************************************************\n", @@ -1973,7 +1927,7 @@ "This version of Ipopt was compiled from source code available at\n", " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", "\n", "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", " for large-scale scientific computation. All technical papers, sales and\n", @@ -1983,7 +1937,7 @@ " computation. See http://www.hsl.rl.ac.uk.\n", "******************************************************************************\n", "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 1236\n", "Number of nonzeros in inequality constraint Jacobian.: 10\n", @@ -2017,112 +1971,150 @@ " 13 -4.3718221e+07 4.53e+04 1.94e+06 -1.0 3.57e+06 - 5.81e-01 3.23e-04h 1\n", " 14 -4.3760623e+07 4.51e+04 4.16e+07 -1.0 3.56e+06 - 4.25e-01 5.93e-03h 1\n", " 15 -4.4646398e+07 7.99e+04 5.37e+07 -1.0 3.54e+06 - 6.75e-01 1.23e-01h 4\n", - " 16 -6.6613749e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", - " 17 -6.5999969e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", - " 18 -6.5249518e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", - " 19 -6.4064695e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", + " 16 -6.6613710e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", + " 17 -6.5999923e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", + " 18 -6.5249462e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", + " 19 -6.4064651e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -6.4051103e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", - " 21 -6.5080976e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", - " 22 -7.5335243e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", - " 23 -7.4658996e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", - " 24 -7.4649764e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", - " 25 -7.4613845e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", - " 26 -7.4421363e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", - " 27 -7.4390154e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n", - " 28 -7.2740081e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", - " 29 -7.2726278e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", + " 20 -6.4051060e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", + " 21 -6.5080931e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", + " 22 -7.5335226e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", + " 23 -7.4658976e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", + " 24 -7.4649744e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", + " 25 -7.4613824e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", + " 26 -7.4421345e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", + " 27 -7.4390136e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n", + " 28 -7.2740056e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", + " 29 -7.2726253e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.2726419e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", - " 31 -8.6665745e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", - " 32 -8.6649468e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", - " 33 -8.6148813e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.44e-02 1.00e+00h 1\n", - " 34 -8.6163785e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", - " 35 -8.6204319e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", - " 36 -8.6333114e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", - " 37 -8.6713987e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", - " 38 -8.7245785e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", - " 39 -9.0563354e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", + " 30 -7.2726394e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", + " 31 -8.6665441e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", + " 32 -8.6649164e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", + " 33 -8.6148490e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.45e-02 1.00e+00h 1\n", + " 34 -8.6163461e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", + " 35 -8.6203995e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", + " 36 -8.6332790e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", + " 37 -8.6713663e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", + " 38 -8.7245413e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", + " 39 -9.0562979e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 40 -9.9476688e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", - " 41 -9.9478624e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", - " 42 -1.0299591e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", - " 43 -1.0299655e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", - " 44 -1.0436244e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", - " 45 -1.0441522e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", - " 46 -1.0438806e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", - " 47 -1.0435495e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", + " 40 -9.9476648e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", + " 41 -9.9478583e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", + " 42 -1.0299584e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", + " 43 -1.0299648e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", + " 44 -1.0436243e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", + " 45 -1.0441521e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", + " 46 -1.0438805e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", + " 47 -1.0435494e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", " 48 -1.0426618e+08 2.01e+03 2.19e+01 -3.8 1.81e+06 - 1.20e-01 1.00e+00h 1\n", " 49 -1.0426992e+08 2.91e+02 3.40e-01 -3.8 6.45e+04 -13.1 1.00e+00 9.64e-01h 1\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.80e+06 - 5.54e-03 2.57e-01h 1\n", - " 51 -1.0427055e+08 2.92e+02 3.97e+02 -3.8 3.24e+06 - 1.33e-01 1.97e-02h 1\n", - " 52 -1.0427008e+08 1.05e+02 1.15e+05 -3.8 2.71e+04 - 7.76e-04 1.00e+00f 1\n", - " 53 -1.0427044e+08 9.41e+01 7.74e+04 -3.8 4.75e+04 -12.6 1.00e+00 3.26e-01h 2\n", - " 54 -1.0427081e+08 9.98e+01 6.24e+04 -3.8 8.03e+04 -13.1 1.00e+00 1.91e-01h 2\n", - " 55 -1.0427080e+08 8.21e-01 1.24e+00 -3.8 7.52e+04 - 1.00e+00 1.00e+00h 1\n", - " 56 -1.0427114e+08 2.09e+01 2.34e+02 -3.8 3.16e+04 -12.7 1.00e+00 4.65e-01h 2\n", - " 57 -1.0427107e+08 4.98e-01 5.37e+00 -3.8 1.61e+04 - 1.00e+00 1.00e+00h 1\n", - " 58 -1.0427121e+08 3.58e+00 1.04e+03 -3.8 1.22e+04 -12.3 1.00e+00 4.79e-01h 2\n", - " 59 -1.0427120e+08 8.56e-03 3.90e+00 -3.8 1.47e+03 - 1.00e+00 1.00e+00h 1\n", + " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.79e+06 - 5.54e-03 2.58e-01h 1\n", + " 51 -1.0427055e+08 2.93e+02 3.98e+02 -3.8 3.24e+06 - 1.33e-01 1.93e-02h 1\n", + " 52 -1.0427009e+08 1.02e+02 1.15e+05 -3.8 2.79e+04 - 7.85e-04 1.00e+00f 1\n", + " 53 -1.0427045e+08 9.18e+01 7.72e+04 -3.8 4.68e+04 -12.6 1.00e+00 3.29e-01h 2\n", + " 54 -1.0427082e+08 9.84e+01 6.22e+04 -3.8 8.09e+04 -13.1 1.00e+00 1.92e-01h 2\n", + " 55 -1.0427081e+08 7.24e-01 1.18e+00 -3.8 7.63e+04 - 1.00e+00 1.00e+00h 1\n", + " 56 -1.0427115e+08 2.08e+01 2.49e+02 -3.8 3.14e+04 -12.7 1.00e+00 4.68e-01h 2\n", + " 57 -1.0427108e+08 6.33e-01 6.20e+00 -3.8 1.65e+04 - 1.00e+00 1.00e+00h 1\n", + " 58 -1.0427122e+08 3.69e+00 9.97e+02 -3.8 1.26e+04 -12.3 1.00e+00 4.66e-01h 2\n", + " 59 -1.0427122e+08 5.22e-05 1.89e-01 -3.8 1.65e+03 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60 -1.0428563e+08 3.80e+04 2.56e+04 -3.8 3.34e+06 - 7.06e-02 1.80e-01f 1\n", + " 61 -1.0428562e+08 3.78e+04 2.55e+04 -3.8 4.32e+05 - 2.18e-02 5.77e-03h 1\n", + " 62 -1.0428017e+08 3.77e+04 2.54e+04 -3.8 1.25e+07 -12.7 7.48e-05 2.34e-03h 9\n", + " 63 -1.0427440e+08 3.74e+04 2.52e+04 -3.8 3.76e+06 -12.3 5.74e-03 7.81e-03h 8\n", + " 64 -1.0427481e+08 3.74e+04 2.52e+04 -3.8 4.44e+05 -9.2 2.60e-01 1.25e-03h 1\n", + " 65 -1.0427459e+08 3.69e+04 2.49e+04 -3.8 4.18e+05 -9.7 3.22e-03 1.13e-02h 1\n", + " 66 -1.0427441e+08 3.69e+04 2.49e+04 -3.8 7.62e+08 -10.1 6.54e-09 7.13e-08f 11\n", + " 67 -1.0427290e+08 3.69e+04 2.49e+04 -3.8 8.98e+05 -9.7 1.79e-03 4.88e-04h 12\n", + " 68 -1.0427211e+08 3.69e+04 2.49e+04 -3.8 7.85e+05 -9.3 1.13e-03 4.88e-04h 12\n", + " 69 -1.0427200e+08 3.69e+04 2.49e+04 -3.8 1.16e+06 -9.8 2.41e-03 2.60e-05h 16\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 60 -1.0427265e+08 3.69e+02 2.06e+03 -3.8 6.13e+04 -12.7 1.00e+00 1.00e+00f 1\n", - " 61 -1.0427267e+08 8.82e-03 8.41e-01 -3.8 2.14e+04 - 1.00e+00 1.00e+00h 1\n", - " 62 -1.0427488e+08 8.81e+02 4.71e+03 -3.8 9.30e+04 -13.2 9.57e-01 1.00e+00h 1\n", - " 63 -1.0427489e+08 1.12e-02 8.43e+03 -3.8 2.41e+04 - 4.26e-01 1.00e+00h 1\n", - " 64 -1.0427588e+08 1.77e+02 2.25e+02 -3.8 4.16e+04 -12.8 1.00e+00 1.00e+00h 1\n", - " 65 -1.0427569e+08 7.17e+00 2.18e+02 -3.8 9.45e+03 - 8.56e-01 1.00e+00h 1\n", - " 66 -1.0427569e+08 3.81e-04 1.34e+03 -3.8 7.69e+02 - 3.56e-01 1.00e+00h 1\n", - " 67 -1.0427568e+08 5.99e-04 1.01e+02 -3.8 7.28e+01 - 6.32e-01 1.00e+00h 1\n", - " 68 -1.0427568e+08 5.44e-04 1.32e+02 -3.8 6.86e+01 - 5.69e-01 1.00e+00h 1\n", - " 69 -1.0427569e+08 3.30e-03 2.05e+01 -3.8 2.50e+02 - 6.00e-01 1.00e+00h 1\n", + " 70 -1.0427193e+08 3.69e+04 2.49e+04 -3.8 4.05e+05 -9.3 2.02e-01 2.35e-04h 5\n", + " 71 -1.0426925e+08 3.69e+04 2.49e+04 -3.8 1.03e+06 -9.8 6.63e-04 6.63e-04s 22\n", + " 72 -1.0425036e+08 3.57e+04 2.41e+04 -3.8 3.87e+05 -9.4 3.17e-02 3.17e-02s 22\n", + " 73 -1.0424520e+08 3.57e+04 2.41e+04 -3.8 1.58e+06 -9.9 9.56e-04 9.56e-04s 22\n", + " 74 -1.0421332e+08 3.51e+04 2.37e+04 -3.8 7.70e+05 -9.4 1.52e-02 1.52e-02s 22\n", + " 75 -1.0409397e+08 3.47e+04 2.34e+04 -3.8 2.08e+06 -9.9 1.36e-02 1.36e-02s 22\n", + " 76 -1.0387838e+08 2.73e+04 1.81e+04 -3.8 3.89e+05 -9.5 2.45e-01 2.45e-01s 22\n", + " 77 -1.0368499e+08 2.52e+04 1.67e+04 -3.8 5.49e+05 -10.0 8.21e-02 8.21e-02s 22\n", + " 78 -1.0298419e+08 2.17e+04 1.42e+04 -3.8 8.63e+05 -10.4 1.56e-01 1.56e-01s 22\n", + " 79 -1.0163132e+08 1.11e+04 6.55e+03 -3.8 5.27e+05 -10.9 6.20e-01 6.20e-01s 22\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 70 -1.0427569e+08 1.33e-05 2.19e+01 -3.8 2.05e+02 - 5.83e-01 1.00e+00h 1\n", - " 71 -1.0427569e+08 1.09e-03 3.63e+00 -3.8 5.68e+02 - 5.94e-01 1.00e+00f 1\n", - " 72 -1.0427569e+08 6.75e-04 3.84e+00 -3.8 1.21e+03 - 5.81e-01 1.00e+00h 1\n", - " 73 -1.0427569e+08 6.52e-03 6.49e-01 -3.8 3.03e+03 - 5.80e-01 1.00e+00h 1\n", - " 74 -1.0427570e+08 3.77e-02 6.80e-01 -3.8 7.51e+03 - 5.69e-01 1.00e+00h 1\n", - " 75 -1.0427573e+08 2.57e-01 1.17e-01 -3.8 1.96e+04 - 5.45e-01 1.00e+00h 1\n", - " 76 -1.0427580e+08 2.17e+00 1.46e-01 -3.8 5.66e+04 - 4.91e-01 1.00e+00h 1\n", - " 77 -1.0427608e+08 3.10e+01 6.00e-02 -3.8 2.13e+05 - 3.77e-01 1.00e+00h 1\n", - " 78 -1.0427817e+08 1.76e+03 5.49e-01 -3.8 1.56e+06 - 1.85e-01 1.00e+00h 1\n", - " 79 -1.0427835e+08 1.67e+03 6.12e-01 -3.8 1.75e+06 - 9.50e-01 6.05e-02h 1\n", + " 80 -1.0194825e+08 1.09e+03 5.66e+02 -3.8 8.31e+04 -11.4 9.54e-01 9.54e-01s 22\n", + " 81 -1.0310109e+08 8.15e+02 4.00e+02 -3.8 5.53e+05 -11.9 2.90e-01 2.90e-01s 22\n", + " 82r-1.0310109e+08 8.15e+02 1.00e+03 -1.6 0.00e+00 -12.4 0.00e+00 0.00e+00R 1\n", + " 83r-1.0310498e+08 2.20e+02 3.18e+03 -1.6 1.50e+03 -4.0 2.25e-03 9.91e-04f 1\n", + " 84r-1.0303151e+08 8.00e+01 3.93e+03 -1.6 8.93e+06 - 3.97e-03 2.67e-03f 1\n", + " 85r-1.0297296e+08 3.79e+01 4.49e+03 -1.6 2.18e+06 - 9.30e-03 7.81e-03f 1\n", + " 86r-1.0295114e+08 8.32e+01 6.01e+03 -1.6 1.88e+06 - 2.57e-02 1.93e-02f 1\n", + " 87r-1.0295645e+08 6.88e+02 7.54e+03 -1.6 1.99e+06 - 6.81e-02 5.54e-02f 1\n", + " 88r-1.0295646e+08 5.58e+02 2.74e+04 -1.6 1.22e+02 -4.5 4.65e-01 1.86e-01f 1\n", + " 89r-1.0253465e+08 4.33e+02 1.34e+04 -1.6 4.11e+05 - 9.66e-01 2.98e-01f 1\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 80 -1.0427838e+08 3.76e-01 2.22e-04 -3.8 9.99e+04 - 1.00e+00 1.00e+00h 1\n", - " 81 -1.0427881e+08 2.24e+00 1.80e+02 -5.7 8.49e+04 - 9.88e-01 1.00e+00h 1\n", - " 82 -1.0427883e+08 9.31e-02 1.16e-03 -5.7 1.69e+04 - 1.00e+00 9.65e-01h 1\n", - " 83 -1.0427883e+08 1.60e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", - " 84 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", - " 85 -1.0427884e+08 5.59e-09 2.35e-13 -8.6 7.18e-01 - 1.00e+00 1.00e+00h 1\n", - " 86 -1.0427884e+08 2.79e-09 9.30e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", + " 90r-1.0417196e+08 5.86e+02 1.34e+04 -1.6 6.16e+06 - 3.39e-01 8.07e-02f 1\n", + " 91r-1.0366409e+08 6.25e+02 2.53e+03 -1.6 1.19e+05 - 2.93e-01 1.00e+00f 1\n", + " 92r-1.0364727e+08 2.09e+02 3.79e+02 -1.6 5.53e+01 -5.0 1.00e+00 6.66e-01h 1\n", + " 93r-1.0365950e+08 8.11e-03 1.47e+00 -1.6 6.58e+01 -5.4 1.00e+00 1.00e+00f 1\n", + " 94r-1.0367534e+08 2.57e-01 2.93e+03 -2.4 2.27e+02 -5.9 1.00e+00 8.08e-01f 1\n", + " 95r-1.0369165e+08 1.08e-01 3.47e+03 -2.4 2.04e+02 -6.4 1.00e+00 6.02e-01f 1\n", + " 96r-1.0369511e+08 2.28e-03 3.84e+00 -2.4 4.36e+01 -6.9 1.00e+00 1.00e+00f 1\n", + " 97r-1.0369311e+08 1.00e+03 1.22e+02 -2.4 1.53e+05 - 7.06e-01 1.00e+00f 1\n", + " 98r-1.0369133e+08 5.34e-02 6.47e-02 -2.4 6.89e+01 -7.3 1.00e+00 1.00e+00h 1\n", + " 99r-1.0364795e+08 1.01e+02 3.37e+02 -3.6 3.26e+04 - 6.54e-01 7.41e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r-1.0309823e+08 3.06e+01 6.46e+02 -3.6 1.67e+05 - 9.13e-01 9.87e-01f 1\n", + " 101r-1.0314314e+08 3.32e-01 6.34e+00 -3.6 1.21e+04 - 1.00e+00 1.00e+00f 1\n", + " 102r-1.0314312e+08 2.74e-05 1.09e-02 -3.6 3.60e+00 -7.8 1.00e+00 1.00e+00h 1\n", + " 103 -1.0319578e+08 9.61e-05 4.23e+01 -3.8 8.11e+03 - 9.97e-01 1.00e+00F 1\n", + " 104 -1.0413984e+08 4.94e+00 1.28e+03 -3.8 1.56e+06 - 8.31e-01 1.60e-01f 1\n", + " 105 -1.0414099e+08 4.85e+00 1.30e+03 -3.8 4.79e+04 - 1.33e-01 1.69e-02h 1\n", + " 106 -1.0417962e+08 1.56e+01 1.28e+03 -3.8 8.29e+06 - 9.95e-04 1.31e-02f 1\n", + " 107 -1.0415007e+08 1.55e+01 1.39e+01 -3.8 9.94e+04 - 9.52e-01 1.00e+00h 1\n", + " 108 -1.0417530e+08 2.20e+02 1.98e-01 -3.8 6.87e+04 - 9.90e-01 9.64e-01h 1\n", + " 109 -1.0428156e+08 1.32e+04 8.97e+01 -3.8 3.02e+06 - 7.12e-01 1.63e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110 -1.0426214e+08 2.88e+02 4.67e+01 -3.8 2.97e+05 - 5.07e-01 1.00e+00h 1\n", + " 111 -1.0426904e+08 1.71e+03 4.37e+01 -3.8 9.53e+06 - 4.40e-02 1.74e-01H 1\n", + " 112 -1.0427745e+08 1.25e+03 2.84e+00 -3.8 1.36e+06 - 9.80e-01 5.51e-01h 1\n", + " 113 -1.0427831e+08 4.62e+02 1.37e-03 -3.8 6.34e+05 - 1.00e+00 1.00e+00h 1\n", + " 114 -1.0427838e+08 1.66e+00 5.16e-06 -3.8 1.36e+04 - 1.00e+00 1.00e+00h 1\n", + " 115 -1.0427881e+08 2.67e+00 2.14e+02 -5.7 8.92e+04 - 9.86e-01 1.00e+00h 1\n", + " 116 -1.0427883e+08 1.12e-01 1.14e-03 -5.7 1.75e+04 - 1.00e+00 9.65e-01h 1\n", + " 117 -1.0427883e+08 2.06e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", + " 118 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", + " 119 -1.0427884e+08 3.73e-09 2.76e-13 -8.6 7.19e-01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120 -1.0427884e+08 1.86e-09 9.31e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", "\n", - "Number of Iterations....: 86\n", + "Number of Iterations....: 120\n", "\n", " (scaled) (unscaled)\n", - "Objective...............: -1.6119507851267775e+02 -1.0427883997848792e+08\n", - "Dual infeasibility......: 9.2995983076271742e-12 6.0160107413515216e-06\n", - "Constraint violation....: 1.0913936421275139e-10 2.7939677238464355e-09\n", - "Complementarity.........: 1.4067955341342552e-11 9.1007124870068398e-06\n", - "Overall NLP error.......: 1.0913936421275139e-10 9.1007124870068398e-06\n", - "\n", - "\n", - "Number of objective function evaluations = 118\n", - "Number of objective gradient evaluations = 87\n", - "Number of equality constraint evaluations = 118\n", - "Number of inequality constraint evaluations = 118\n", - "Number of equality constraint Jacobian evaluations = 87\n", - "Number of inequality constraint Jacobian evaluations = 87\n", - "Number of Lagrangian Hessian evaluations = 86\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.121\n", - "Total CPU secs in NLP function evaluations = 0.009\n", + "Objective...............: -1.6119507851267775e+02 -1.0427883997848789e+08\n", + "Dual infeasibility......: 9.3067037146559845e-12 6.0206073060194729e-06\n", + "Constraint violation....: 1.0913936421275139e-10 1.8626451492309570e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 1.4067955341264719e-11 9.1007124869564871e-06\n", + "Overall NLP error.......: 1.0913936421275139e-10 9.1007124869564871e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 255\n", + "Number of objective gradient evaluations = 101\n", + "Number of equality constraint evaluations = 255\n", + "Number of inequality constraint evaluations = 255\n", + "Number of equality constraint Jacobian evaluations = 121\n", + "Number of inequality constraint Jacobian evaluations = 121\n", + "Number of Lagrangian Hessian evaluations = 120\n", + "Total seconds in IPOPT = 0.174\n", "\n", "EXIT: Optimal Solution Found.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", "component keys that are not exported as part of the NL file. Skipping.\n", "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", "that are not Var, Constraint, Objective, or the model. Skipping.\n", - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", "\n", "\n", "******************************************************************************\n", @@ -2133,7 +2125,7 @@ "This version of Ipopt was compiled from source code available at\n", " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", "\n", "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", " for large-scale scientific computation. All technical papers, sales and\n", @@ -2143,7 +2135,7 @@ " computation. See http://www.hsl.rl.ac.uk.\n", "******************************************************************************\n", "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 1236\n", "Number of nonzeros in inequality constraint Jacobian.: 10\n", @@ -2185,17 +2177,18 @@ " 20 -1.0427883e+08 1.02e+00 6.20e-03 -5.7 6.34e+04 - 1.00e+00 9.13e-01h 1\n", " 21 -1.0427883e+08 2.22e-03 7.11e-08 -5.7 2.00e+03 - 1.00e+00 1.00e+00f 1\n", " 22 -1.0427884e+08 2.66e-03 1.10e-05 -8.6 3.26e+03 - 1.00e+00 1.00e+00h 1\n", - " 23 -1.0427884e+08 1.16e-08 1.82e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", - " 24 -1.0427884e+08 3.14e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", + " 23 -1.0427884e+08 1.16e-08 1.87e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", + " 24 -1.0427884e+08 4.19e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", "\n", "Number of Iterations....: 24\n", "\n", " (scaled) (unscaled)\n", - "Objective...............: -7.4466968713582915e+01 -1.0427883997850099e+08\n", - "Dual infeasibility......: 2.0257749320973842e-11 2.8367672758258825e-05\n", - "Constraint violation....: 1.3824319466948509e-10 3.1432136893272400e-09\n", - "Complementarity.........: 6.5249453183277711e-12 9.1371213367821990e-06\n", - "Overall NLP error.......: 1.3824319466948509e-10 2.8367672758258825e-05\n", + "Objective...............: -7.4466968713582887e+01 -1.0427883997850095e+08\n", + "Dual infeasibility......: 2.0257749632681967e-11 2.8367673194755198e-05\n", + "Constraint violation....: 1.3824319466948509e-10 4.1909515857696533e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 6.5249453183278187e-12 9.1371213367822650e-06\n", + "Overall NLP error.......: 1.3824319466948509e-10 2.8367673194755198e-05\n", "\n", "\n", "Number of objective function evaluations = 52\n", @@ -2205,43 +2198,42 @@ "Number of equality constraint Jacobian evaluations = 25\n", "Number of inequality constraint Jacobian evaluations = 25\n", "Number of Lagrangian Hessian evaluations = 24\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.028\n", - "Total CPU secs in NLP function evaluations = 0.003\n", + "Total seconds in IPOPT = 0.026\n", "\n", "EXIT: Optimal Solution Found.\n", "Optimal solution process results:\n", "\n", "\n", - "Extent of reaction: 311.30698549500477\n", + "Extent of reaction: 311.3069854950048\n", "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", + "CH4 : -0.0\n", "H2 : -2.0\n", "CH3OH : 1.0\n", "CO : -1.0\n", "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", "\n", "Reaction conversion: 0.8500000099996615\n", - "Reactor duty (MW): -59.340221072991014\n", - "Duty from Reaction (MW)): 28.216865165267233\n", - "Compressor work (MW): 1.2861669211016399e-24\n", - "Turbine work (MW): -2.4913012083840025\n", - "Feed Mixer outlet temperature (C)): 20.05171421375354\n", - "Recycle Mixer outlet temperature (C)): 41.54321437801775\n", - "Feed Compressor outlet temperature (C)): 41.54321437801792\n", + "Reactor duty (MW): -59.34022107299101\n", + "Duty from Reaction (MW)): 28.216865165267237\n", + "Compressor work (MW): -4.7980486241206324e-24\n", + "Turbine work (MW): -2.491301208383993\n", + "Feed Mixer outlet temperature (C)): 20.051714213753485\n", + "Recycle Mixer outlet temperature (C)): 41.54321437801826\n", + "Feed Compressor outlet temperature (C)): 41.54321437801826\n", "Feed Compressor outlet pressure (Pa)): 5100000.0\n", "Heater outlet temperature (C)): 215.0\n", "Reactor outlet temperature (C)): 231.85000478422364\n", - "Turbine outlet temperature (C)): 141.50037862882152\n", - "Turbine outlet pressure (Pa)): 1487177.2483574792\n", + "Turbine outlet temperature (C)): 141.50037862882186\n", + "Turbine outlet pressure (Pa)): 1487177.2483574806\n", "Cooler outlet temperature (C)): 52.56999699077659\n", "Flash outlet temperature (C)): 134.0\n", "Purge percentage (amount of vapor vented to exhaust): 9.999999000026644 %\n", - "Methanol recovery(%): 92.05882105498138\n", - "annualized capital cost ($/year) = 259559.90821288762\n", - "operating cost ($/year) = 525130020.7095608\n", - "sales ($/year) = 140033684437.2827\n", + "Methanol recovery(%): 92.05882105498134\n", + "annualized capital cost ($/year) = 259559.90821288814\n", + "operating cost ($/year) = 525130020.70956033\n", + "sales ($/year) = 140033684437.28268\n", "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 104278839.97850098\n", + "revenue (1000$/year)= 104278839.97850095\n", "\n", "\n", "====================================================================================\n", @@ -2302,7 +2294,77 @@ ] } ], - "execution_count": 17 + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", + "m.fs.S101.split_fraction_lb = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", + ") # min 10% purge\n", + "m.fs.S101.split_fraction_ub = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", + ") # max 50% purge\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "\n", + "# Pass 1: smoothed VLE transition\n", + "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "\n", + "\n", + "solver.options[\"max_iter\"] = 200\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "# Pass 2: restore default smoothness\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, { "cell_type": "markdown", @@ -2313,15 +2375,17 @@ }, { "cell_type": "code", + "execution_count": 18, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-20T21:01:13.770912800Z", "start_time": "2026-02-20T21:01:13.761945900Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# testing model results\n", "assert value(m.fs.R101.rate_reaction_extent[0, \"R1\"]) == pytest.approx(\n", @@ -2335,9 +2399,7 @@ " 10.0000, rel=1e-5\n", ")\n", "assert value(m.fs.objective) / 1e6 == pytest.approx(104.2789, rel=1e-5)" - ], - "outputs": [], - "execution_count": 18 + ] }, { "cell_type": "markdown", @@ -2349,15 +2411,15 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-02-20T21:01:13.775587500Z", "start_time": "2026-02-20T21:01:13.771970400Z" } }, - "source": [], "outputs": [], - "execution_count": 18 + "source": [] } ], "metadata": { @@ -2377,7 +2439,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.13.0" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_doc.ipynb b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_doc.ipynb index 10e643c8..a53c5103 100644 --- a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_doc.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_doc.ipynb @@ -1,4180 +1,2321 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:08.793234700Z", - "start_time": "2026-02-20T21:01:08.784498Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:12.243314Z", - "iopub.status.busy": "2026-02-20T21:02:12.242299Z", - "iopub.status.idle": "2026-02-20T21:02:12.246325Z", - "shell.execute_reply": "2026-02-20T21:02:12.246325Z" - }, - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Methanol Synthesis Flowsheet Example\n", - "Maintainer: Brandon Paul \n", - "Author: Brandon Paul \n", - "Updated: 2023-06-01 \n", - "\n", - "The purpose of this notebook is to demonstrate flowsheet synthesis integrating IDAES modeling tools, including the Unit Model Library, Property and Reaction Framework, IDAES scaling tools and the Process Costing Framework. The example leverages imports from external flowsheet scripts, and demonstrates implementation of separate VLE and vapor-only property packages to reduce model complexity where applicable.\n", - "\n", - "## Simplified Hydrogen Reformation System\n", - "\n", - "This example demonstrates a steady-state model of methanol synthesis from hydrogen and carbon monoxide. To simulate relevant natural gas components, the reactant vapors are mixed stoichiometrically and brought to optimal reaction conditions prior to entering the gas-phase reactor. Vapor liquid equilibrium is mainly applicable in the post-reactor Flash unit for methanol recovery, and is accounted for by separate vapor and VLE thermophysical property packages. See `methanol_flowsheet.py` for more information on how to assemble the flowsheet, as well as [idaes_examples.mod.methanol.methanol_ideal_VLE.py](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_VLE.py), [idaes_examples.mod.methanol.methanol_ideal_vapor](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_vapor.py) and [idaes_examples.mod.methanol.methanol_reactions](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_reactions.py) for more information on the thermophyscial and reaction properties.\n", - "\n", - "This example is a reasonable approximation for gas-phase methanol synthesis systems and does not represent any particular chemical process. To simplify the system and increase tractability, hydrogen and carbon monoxide feeds are considered in lieu of multi-step mechanisms for carbon dioxide conversion to methanol. General process descriptions for gas-phase synthesis, as well as thermophysical and reaction properties for carbon monoxide hydrogenation, were taken from the following publication:\n", - "\n", - "Nieminen, H.; Laari, A.; Koiranen, T. CO2 Hydrogenation to Methanol by a Liquid-Phase Process with Alcoholic Solvents: A Techno-Economic Analysis. Processes 2019, 7, 405. https://doi.org/10.3390/pr7070405" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. Introduction\n", - "\n", - "This example demonstrates a simulation of methanol synthesis from hydrogen and carbon monoxide. Each methanol flowsheet module includes several built-in methods. This notebook demonstrates building the flowsheet, implementing model scaling, initialization and solving a square problem, costing and final constrained optimization.\n", - "\n", - "The ```build_model()``` method creates the Pyomo concrete model and builds the flowsheet by importing thermophysical and reaction properties and unit models and defining stream connections between these units. This method also implements appropriate default scaling on state and property variables.\n", - "\n", - "The ```set_inputs()``` method adds the appropriate initial specifications on the feed streams and unit operations. Specifications upstream of the reactor largely remain fixed throughout the optimization.\n", - "\n", - "The ```scale_flowsheet()``` method implements generic variable, unit model state variable, unit model constraint and Arc equality constraint scaling via IDAES scaling tools. Scaling factors are hard-coded in the flowsheet scripts to adjust for order of magnitude factors in appropriate constraints and simplify numerical solver calculations.\n", - "\n", - "The ```initialize_flowsheet()``` method uses the initial guess to initialize the models sequentially, solving each unit and propagating the results to the outlet stream to converge the next unit more quickly. This occurs just before the flowsheet-level solver call.\n", - "\n", - "The ```add_costing()``` method creates new variables and constraints related to unit model capital cost and operating cost calculations, and defines an objective function for the process economics. This method is called after the flowsheet-level solver call, and the flowsheet is resolved once costing is added. Capital costs are estimated using built-in costing methods within IDAES, and operating costs are estimated from a combination of known cost coefficients and surrogate models.\n", - "\n", - "The ```report()``` method displays relevant model results after the flowsheet has been fully solved." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2. Problem Statement \n", - "\n", - "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", - "\n", - "## 2.1. Main Inputs: \n", - "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", - "- Pre-reactor compressor outlet pressure (Pa)\n", - "- Pre-reactor heater outlet temperature (K)\n", - "\n", - "## 2.2. Main Outputs:\n", - "- Extent of reaction (mol/s)\n", - "- Reactor duty (W)\n", - "- Turbine duty (W)\n", - "- Methanol recovery (%)\n", - "- Annual revenue (USD/year)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:08.820779700Z", - "start_time": "2026-02-20T21:01:08.801334300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:12.247834Z", - "iopub.status.busy": "2026-02-20T21:02:12.247834Z", - "iopub.status.idle": "2026-02-20T21:02:12.253383Z", - "shell.execute_reply": "2026-02-20T21:02:12.253383Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3. Import and Solve Flowsheet\n", - "## 3.1 Import Pyomo and IDAES Libraries" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, let's import the relevant Pyomo and IDAES Libraries:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:11.424944700Z", - "start_time": "2026-02-20T21:01:08.826325100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:12.283314Z", - "iopub.status.busy": "2026-02-20T21:02:12.282304Z", - "iopub.status.idle": "2026-02-20T21:02:14.904598Z", - "shell.execute_reply": "2026-02-20T21:02:14.904598Z" - } - }, - "outputs": [], - "source": [ - "import pytest\n", - "import os\n", - "\n", - "# Import Pyomo libraries\n", - "from pyomo.environ import (\n", - " Constraint,\n", - " Objective,\n", - " Var,\n", - " Expression,\n", - " Param,\n", - " ConcreteModel,\n", - " TransformationFactory,\n", - " value,\n", - " maximize,\n", - " units as pyunits,\n", - ")\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.network import Arc\n", - "\n", - "# Import IDAES core libraries\n", - "from idaes.core import FlowsheetBlock\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util import scaling as iscale\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "from idaes.core.util.initialization import propagate_state\n", - "\n", - "# Import required property modules\n", - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "\n", - "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", - "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", - "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", - "\n", - "from idaes.models.unit_models import (\n", - " Feed,\n", - " Mixer,\n", - " Heater,\n", - " Compressor,\n", - " Turbine,\n", - " StoichiometricReactor,\n", - " Flash,\n", - " Product,\n", - ")\n", - "from idaes.models.unit_models.mixer import MomentumMixingType\n", - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core import UnitModelCostingBlock\n", - "from idaes.models.costing.SSLW import SSLWCosting\n", - "\n", - "# import flowsheet functions\n", - "from methanol_flowsheet import (\n", - " build_model,\n", - " set_inputs,\n", - " scale_flowsheet,\n", - " initialize_flowsheet,\n", - " add_costing,\n", - " report,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.2 Build and Solve Flowsheet\n", - "The methanol flowsheet methods are called sequentially below, following the workflow contained in the ```main()``` method in `methanol_flowsheet.py`. First, let's set the solver options. IDAES contains a default solver `get_solver` which calls IPOPT using standard settings, and we set an iteration cap of 100 to catch nonconverging solver runs." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:11.432823800Z", - "start_time": "2026-02-20T21:01:11.426117300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:14.907115Z", - "iopub.status.busy": "2026-02-20T21:02:14.905612Z", - "iopub.status.idle": "2026-02-20T21:02:14.909354Z", - "shell.execute_reply": "2026-02-20T21:02:14.909354Z" - } - }, - "outputs": [], - "source": [ - "# Set solver options\n", - "solver = get_solver() # IPOPT\n", - "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", - "solver.options = optarg" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will build and solve the initial flowsheet using imported flowsheet methods - see `methanol_flowsheet.py` for complete method scripts.\n", - "\n", - "In the code below, we first define a Pyomo model object and build the model by defining each unit block with relevant property packages. As mentioned earlier, only the Flash unit (and the liquid outlet Product block) employ the VLE property package to ensure fast convergence of vapor-only processes.\n", - "\n", - "The process inputs are set for stoichiometric hydrogen and carbon monoxide feeds according to the process diagram in section 2.2. In the output below, the script returns the expected degrees of freedom for the model for each unit (compressor pressure change, heater duty, reactor duty and conversion, turbine pressure change and efficiency, cooler duty and flash duty and pressure change) and the actual model degrees of freedom before input specification, after the feed inputs are specified (flow, enthalpy, pressure, and composition for each feed) and after the unit model inputs are specified.\n", - "\n", - "After setting process inputs, we have a square problem for initialization. Here, we first implement IDAES scaling tools to create a more tractable problem during the solve step, and then sequentially initialize and propagate results from each unit block. As expected, the model only performs dew and bubble point calculations for the Flash and CH3OH product blocks where liquid phases are present and we obtain a square, solved problem:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:14.052603900Z", - "start_time": "2026-02-20T21:01:11.433413300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:14.910861Z", - "iopub.status.busy": "2026-02-20T21:02:14.910861Z", - "iopub.status.idle": "2026-02-20T21:02:16.329145Z", - "shell.execute_reply": "2026-02-20T21:02:16.329145Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unit degrees of freedom\n", - "M101 0\n", - "C101 1\n", - "H101 1\n", - "R101 2\n", - "T101 2\n", - "H102 1\n", - "F101 2\n", - "Total DOF: 23\n", - "DOF after streams specified: 9\n", - "DOF after units specified: 0\n", - "\n", - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H2.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H2: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.CO.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.CO: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:15 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:16 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF before solve: 0\n", - "\n", - "Solving initial problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 955\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 607\n", - "\n", - "Total number of variables............................: 310\n", - " variables with only lower bounds: 35\n", - " variables with lower and upper bounds: 258\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 310\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 2.79e+02 2.77e+00 -1.0 1.00e-02 - 9.90e-01 9.90e-01h 1\n", - " 2 0.0000000e+00 2.77e+00 1.21e+00 -1.0 1.00e-04 - 9.90e-01 9.90e-01h 1\n", - " 3 0.0000000e+00 6.98e-10 1.00e+03 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 3\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Constraint violation....: 1.1368683772161603e-13 6.9849193096160889e-10\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 1.1368683772161603e-13 6.9849193096160889e-10\n", - "\n", - "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.003\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - } - ], - "source": [ - "# Build and solve flowsheet\n", - "m = ConcreteModel()\n", - "build_model(m) # build flowsheet by adding unit models and property packages\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "\n", - "results = solver.solve(m, tee=True) # initial square problem solve" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.3 Flowsheet Costing and Optimization\n", - "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs. Additional, we calculate reactor operating costs as a function of conversion and assume constant rates for electricity, heating and cooling costs. Capital costs are annualized over 15 years, and revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, including a check on the reaction stoichiometry, relevant duty and state variable values, economic results, and stream tables for feed and product streams:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:14.190744700Z", - "start_time": "2026-02-20T21:01:14.053656100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:16.331152Z", - "iopub.status.busy": "2026-02-20T21:02:16.331152Z", - "iopub.status.idle": "2026-02-20T21:02:16.452173Z", - "shell.execute_reply": "2026-02-20T21:02:16.452173Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving with costing...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 971\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 611\n", - "\n", - "Total number of variables............................: 319\n", - " variables with only lower bounds: 43\n", - " variables with lower and upper bounds: 258\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 319\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8492051e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.9068962e+07 5.76e+04 6.45e+01 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", - " 2 -2.9074767e+07 5.71e+02 9.98e+00 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", - " 3 -2.9074825e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9074825e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 4\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -4.4948186430824137e+01 -2.9074824816033222e+07\n", - "Dual infeasibility......: 3.6708958239217049e-07 2.3745263485255724e-01\n", - "Constraint violation....: 4.5474735088646412e-12 1.0477378964424133e-09\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 2.3745263485255724e-01\n", - "\n", - "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.006\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initial solution process results:\n", - "\n", - "\n", - "Extent of reaction: 237.6004779\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.21917830318435\n", - "Duty from Reaction (MW)): 21.536107316856\n", - "Turbine work (MW): -0.9593346445867499\n", - "Mixer outlet temperature (C)): 20.051714213753257\n", - "Compressor outlet temperature (C)): 20.051714213753257\n", - "Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.8781524424324\n", - "Turbine outlet pressure (Pa)): 3100000.0\n", - "Cooler outlet temperature (C)): 134.0\n", - "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 60.004430129216836\n", - "annualized capital cost ($/year) = 219790.5044704343\n", - "operating cost ($/year) = 380701687.4964806\n", - "sales ($/year) = 64685201172.198135\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29074824.816033214\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 336.23\n", - " Total Mole Fraction CH4 dimensionless 2.8373e-06\n", - " Total Mole Fraction CO dimensionless 0.23555\n", - " Total Mole Fraction H2 dimensionless 0.48181\n", - " Total Mole Fraction CH3OH dimensionless 0.28263\n", - " Molar Enthalpy joule / mole -80218.\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 142.57\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3813e+05\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "print(\"Solving with costing...\")\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:14.325574400Z", - "start_time": "2026-02-20T21:01:14.190744700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:16.454455Z", - "iopub.status.busy": "2026-02-20T21:02:16.453435Z", - "iopub.status.idle": "2026-02-20T21:02:16.561300Z", - "shell.execute_reply": "2026-02-20T21:02:16.561300Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Solving optimization problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 975\n", - "Number of nonzeros in inequality constraint Jacobian.: 8\n", - "Number of nonzeros in Lagrangian Hessian.............: 613\n", - "\n", - "Total number of variables............................: 322\n", - " variables with only lower bounds: 43\n", - " variables with lower and upper bounds: 259\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 318\n", - "Total number of inequality constraints...............: 8\n", - " inequality constraints with only lower bounds: 4\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 4\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8492012e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.8402807e+07 2.72e+04 9.71e+01 -1.0 8.82e+06 - 4.99e-02 2.59e-02h 1\n", - " 2 -2.8406592e+07 2.70e+04 9.55e+01 -1.0 8.56e+06 - 7.51e-02 8.58e-03h 1\n", - " 3 -2.8493711e+07 2.29e+04 3.69e+02 -1.0 8.41e+06 - 1.67e-01 1.52e-01h 1\n", - " 4 -2.8493256e+07 2.28e+04 1.20e+04 -1.0 4.60e+06 - 1.00e-01 2.61e-03h 1\n", - " 5 -2.8504483e+07 2.24e+04 1.20e+04 -1.0 4.52e+06 - 2.44e-02 2.38e-02h 1\n", - " 6 -2.8536508e+07 2.16e+04 2.28e+04 -1.0 4.39e+06 - 5.48e-02 6.86e-02h 1\n", - " 7 -2.8537589e+07 2.16e+04 1.35e+05 -1.0 3.94e+06 - 2.56e-01 2.49e-03h 1\n", - " 8 -2.8537637e+07 2.15e+04 6.77e+06 -1.0 1.30e+06 - 4.68e-01 1.17e-04h 1\n", - " 9 -2.8910081e+07 8.51e+04 2.07e+06 -1.0 1.31e+06 - 4.38e-01 9.05e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -2.8916017e+07 7.81e+04 1.11e+08 -1.0 9.39e+04 -4.0 3.56e-03 8.26e-02h 1\n", - " 11 -2.8916050e+07 7.80e+04 1.11e+08 -1.0 8.73e+04 -4.5 9.12e-02 9.05e-04h 1\n", - " 12 -2.8951501e+07 1.29e+04 3.00e+07 -1.0 8.73e+04 - 1.37e-02 9.90e-01h 1\n", - " 13 -2.8964697e+07 3.52e+03 9.82e+06 -1.0 2.95e+04 - 8.80e-01 9.92e-01h 1\n", - " 14 -2.9150638e+07 4.25e+00 6.53e+07 -1.0 1.59e+04 - 9.88e-01 1.00e+00h 1\n", - " 15 -3.2694771e+07 3.47e+03 1.38e+08 -1.0 3.00e+05 - 3.58e-01 1.00e+00f 1\n", - " 16 -3.9657884e+07 3.74e+02 4.98e+06 -1.0 6.48e+05 - 9.11e-01 1.00e+00F 1\n", - " 17 -5.8700677e+07 2.03e+04 1.12e+06 -1.0 2.00e+06 - 2.65e-01 1.00e+00F 1\n", - " 18 -7.8085174e+07 1.40e+05 4.14e+05 -1.0 4.34e+06 - 7.55e-01 7.57e-01f 1\n", - " 19 -7.9333792e+07 1.60e+05 2.63e+05 -1.0 3.52e+06 - 9.63e-01 3.03e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -7.7164009e+07 3.20e+03 7.59e+03 -1.0 4.56e+05 - 9.91e-01 1.00e+00h 1\n", - " 21 -7.7545831e+07 3.83e+03 5.53e+01 -1.0 2.78e+05 - 1.00e+00 1.00e+00h 1\n", - " 22 -7.7683360e+07 9.76e+02 2.23e+06 -2.5 6.32e+04 - 1.00e+00 7.70e-01h 1\n", - " 23 -7.7696221e+07 8.35e+00 1.48e+02 -2.5 6.87e+04 - 1.00e+00 1.00e+00h 1\n", - " 24 -7.7696183e+07 8.31e-03 4.61e-03 -2.5 2.13e+03 - 1.00e+00 1.00e+00h 1\n", - " 25 -7.7699949e+07 5.36e+00 1.27e+04 -5.7 7.60e+04 - 9.49e-01 9.94e-01f 1\n", - " 26 -7.7700458e+07 8.84e+01 1.03e+03 -5.7 3.66e+05 - 9.25e-01 9.72e-01h 1\n", - " 27 -7.7700530e+07 1.74e+01 1.01e+01 -5.7 6.59e+04 - 1.00e+00 8.03e-01h 1\n", - " 28 -7.7700531e+07 2.07e-04 4.22e-06 -5.7 1.25e+03 - 1.00e+00 1.00e+00h 1\n", - " 29 -7.7700536e+07 9.48e-04 1.29e-01 -8.6 1.69e+03 - 1.00e+00 9.99e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.7700536e+07 6.52e-09 5.32e-11 -8.6 1.52e+00 - 1.00e+00 1.00e+00f 1\n", - " 31 -7.7700536e+07 8.38e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 31\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -1.2012103932708916e+02 -7.7700535938862860e+07\n", - "Dual infeasibility......: 6.9713197782916848e-11 4.5094122229452131e-05\n", - "Constraint violation....: 9.4587448984384537e-11 8.3819031715393066e-09\n", - "Complementarity.........: 1.4074777632989367e-11 9.1042982264387185e-06\n", - "Overall NLP error.......: 9.4587448984384537e-11 4.5094122229452131e-05\n", - "\n", - "\n", - "Number of objective function evaluations = 34\n", - "Number of objective gradient evaluations = 32\n", - "Number of equality constraint evaluations = 34\n", - "Number of inequality constraint evaluations = 34\n", - "Number of equality constraint Jacobian evaluations = 32\n", - "Number of inequality constraint Jacobian evaluations = 32\n", - "Number of Lagrangian Hessian evaluations = 31\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.021\n", - "Total CPU secs in NLP function evaluations = 0.006\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal solution process results:" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\n", - "Extent of reaction: 269.2805447879921\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.8500000099999546\n", - "Reactor duty (MW): -51.363573577545786\n", - "Duty from Reaction (MW)): 24.407588579583603\n", - "Turbine work (MW): -1.9904899177794815\n", - "Mixer outlet temperature (C)): 20.0517142137536\n", - "Compressor outlet temperature (C)): 20.0517142137536\n", - "Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 231.85000468716584\n", - "Turbine outlet temperature (C)): 139.85888172675686\n", - "Turbine outlet pressure (Pa)): 1427653.3547820917\n", - "Cooler outlet temperature (C)): 52.56999709299214\n", - "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 92.8035547465754\n", - "annualized capital cost ($/year) = 235547.18924473316\n", - "operating cost ($/year) = 451663512.6847629\n", - "sales ($/year) = 113381889876.90082\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 77700535.93886285\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 165.54\n", - " Total Mole Fraction CH4 dimensionless 5.7630e-06\n", - " Total Mole Fraction CO dimensionless 0.28706\n", - " Total Mole Fraction H2 dimensionless 0.59587\n", - " Total Mole Fraction CH3OH dimensionless 0.11706\n", - " Molar Enthalpy joule / mole -52313.\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 249.90\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3792e+05\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "opt_res = solver.solve(m, tee=True)\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, the process achieves a much greater revenue as a result of increasing conversion and lowering the inlet temperature to the Flash unit to encourage methanol recovery in the liquid phase. The results show a slight increase in equipment and operating costs from these changes, as well as a small loss of methanol in the exhaust." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 4. Problem Statement - Analyzing Benefit of Recycling Flash Vapor\n", - "\n", - "To increase the efficiency of the process as well as overall methanol production and revenue, we can add a recycle stream to send most of the Flash vapor back to the start of the process. This will reduce methanol loss in the exhaust and increase feed utilization, resulting in increased operating costs and increased production (revenue) at the same conversion. Note that for conversions less than 100%, a simulation with no purge will never converge due to accumulation of gases within the system. Therefore, to ensure we close the mass balance we set a lower bound at 10% purge from the Flash vapor to the exhaust. We expect to see a marginal increase in operating costs due to increased flow, and a much larger increase in overall production resulting in a higher total revenue.\n", - "\n", - "By adding a recycle to the flowsheet, we significantly decrease the tractability of the problem and require a better initial guess. The SequentialDecomposition algorithm automatically determines a stream to *tear*, or use to break the solve loop, and iterates from a set of user-supplied initial guesses until converging on the optimal solution. The code below calls an initialization method to automatically determine the tear stream. See the initialization method of `methanol_flowsheet_w_recycle.py` for further details Sequential Decomposition scheme.\n", - "\n", - "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", - "\n", - "## 4.1. Main Inputs: \n", - "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", - "- Pre-reactor compressor outlet pressure (Pa)\n", - "- Pre-reactor heater outlet temperature (K)\n", - "\n", - "## 4.2. Main Outputs:\n", - "- Extent of reaction (mol/s)\n", - "- Reactor duty (W)\n", - "- Compressor duty (W)\n", - "- Turbine duty (W)\n", - "- Methanol recovery (%)\n", - "- Purge percentage (%)\n", - "- Annual revenue (USD/year)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:14.336449800Z", - "start_time": "2026-02-20T21:01:14.325574400Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:16.563343Z", - "iopub.status.busy": "2026-02-20T21:02:16.562311Z", - "iopub.status.idle": "2026-02-20T21:02:16.566882Z", - "shell.execute_reply": "2026-02-20T21:02:16.566882Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet_recycle.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 5. Import and Solve Recycle Flowsheet\n", - "## 5.1 Import Pyomo and IDAES Libraries\n", - "As we are rebuilding the model, we need to import require Pyomo and IDAES libraries:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:14.352741300Z", - "start_time": "2026-02-20T21:01:14.336982200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:16.567927Z", - "iopub.status.busy": "2026-02-20T21:02:16.567927Z", - "iopub.status.idle": "2026-02-20T21:02:16.574038Z", - "shell.execute_reply": "2026-02-20T21:02:16.574038Z" - } - }, - "outputs": [], - "source": [ - "import pytest\n", - "import os\n", - "\n", - "# Import Pyomo libraries\n", - "from pyomo.environ import (\n", - " Constraint,\n", - " Objective,\n", - " Var,\n", - " Expression,\n", - " Param,\n", - " ConcreteModel,\n", - " TransformationFactory,\n", - " value,\n", - " maximize,\n", - " units as pyunits,\n", - ")\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.network import Arc, SequentialDecomposition\n", - "\n", - "# Import IDAES core libraries\n", - "from idaes.core import FlowsheetBlock\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util import scaling as iscale\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "from idaes.core.util.initialization import propagate_state\n", - "\n", - "# Import required models\n", - "\n", - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "\n", - "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", - "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", - "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", - "\n", - "from idaes.models.unit_models import (\n", - " Feed,\n", - " Mixer,\n", - " Heater,\n", - " Compressor,\n", - " Turbine,\n", - " StoichiometricReactor,\n", - " Flash,\n", - " Separator as Splitter,\n", - " Product,\n", - ")\n", - "from idaes.models.unit_models.mixer import MomentumMixingType\n", - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core import UnitModelCostingBlock\n", - "from idaes.models.costing.SSLW import SSLWCosting\n", - "import idaes.logger as idaeslog\n", - "\n", - "# import flowsheet functions\n", - "from methanol_flowsheet_w_recycle import (\n", - " build_model,\n", - " set_inputs,\n", - " scale_flowsheet,\n", - " initialize_flowsheet,\n", - " add_costing,\n", - " report,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.2 Build and Solve Recycle Flowsheet\n", - "As before, we will first build the flowsheet, set required inputs, initialize and solve a square problem. Recycling methanol to pre-reactor blocks complicates VLE calculations, and limiting VLE calculations to the Flash unit and liquid Product block greatly increases tractability during initialization. All initial feed and unit specifications are identical to the non-recycle case; the Sequential Decomposition algorithm automatically selects the compressor feed as the tear stream and uses \"no recycle\" results as a first guess. In the output below, the solver solves all units and then resolves select blocks with updated inlet results, followed by a full flowsheet solve:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:17.493149400Z", - "start_time": "2026-02-20T21:01:14.352741300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:16.575088Z", - "iopub.status.busy": "2026-02-20T21:02:16.575088Z", - "iopub.status.idle": "2026-02-20T21:02:19.340983Z", - "shell.execute_reply": "2026-02-20T21:02:19.340473Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unit degrees of freedom\n", - "M101 0\n", - "C101 1\n", - "H101 1\n", - "R101 2\n", - "T101 2\n", - "H102 1\n", - "F101 2\n", - "M102 0\n", - "S101 1\n", - "Total DOF: 24\n", - "DOF after streams specified: 10\n", - "DOF after units specified: 0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Tear Stream:\n", - "fs.s02 : fs.M102.outlet to fs.C101.inlet\n", - "\n", - "Calculation order:\n", - "fs.H2\n", - "fs.M101\n", - "fs.R101\n", - "fs.T101\n", - "fs.H102\n", - "fs.F101\n", - "fs.S101\n", - "fs.EXHAUST\n", - "\n", - "Initial DOF = 0\n", - "Solving fs.H2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.CO\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.C101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.M101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.H101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.R101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.T101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "Solving fs.H102\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.F101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.S101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.CH3OH\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.EXHAUST\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.M102\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.H2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "Solving fs.CO\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.M101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.EXHAUST\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:04.629603300Z", + "start_time": "2026-02-20T21:01:04.619279Z" + }, + "tags": [ + "header", + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Methanol Synthesis Flowsheet Example\n", + "Maintainer: Brandon Paul \n", + "Author: Brandon Paul \n", + "Updated: 2023-06-01 \n", + "\n", + "The purpose of this notebook is to demonstrate flowsheet synthesis integrating IDAES modeling tools, including the Unit Model Library, Property and Reaction Framework, IDAES scaling tools and the Process Costing Framework. The example leverages imports from external flowsheet scripts, and demonstrates implementation of separate VLE and vapor-only property packages to reduce model complexity where applicable.\n", + "\n", + "## Simplified Hydrogen Reformation System\n", + "\n", + "This example demonstrates a steady-state model of methanol synthesis from hydrogen and carbon monoxide. To simulate relevant natural gas components, the reactant vapors are mixed stoichiometrically and brought to optimal reaction conditions prior to entering the gas-phase reactor. Vapor liquid equilibrium is mainly applicable in the post-reactor Flash unit for methanol recovery, and is accounted for by separate vapor and VLE thermophysical property packages. See `methanol_flowsheet.py` for more information on how to assemble the flowsheet, as well as [idaes_examples.mod.methanol.methanol_ideal_VLE.py](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_VLE.py), [idaes_examples.mod.methanol.methanol_ideal_vapor](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_vapor.py) and [idaes_examples.mod.methanol.methanol_reactions](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_reactions.py) for more information on the thermophyscial and reaction properties.\n", + "\n", + "This example is a reasonable approximation for gas-phase methanol synthesis systems and does not represent any particular chemical process. To simplify the system and increase tractability, hydrogen and carbon monoxide feeds are considered in lieu of multi-step mechanisms for carbon dioxide conversion to methanol. General process descriptions for gas-phase synthesis, as well as thermophysical and reaction properties for carbon monoxide hydrogenation, were taken from the following publication:\n", + "\n", + "Nieminen, H.; Laari, A.; Koiranen, T. CO2 Hydrogenation to Methanol by a Liquid-Phase Process with Alcoholic Solvents: A Techno-Economic Analysis. Processes 2019, 7, 405. https://doi.org/10.3390/pr7070405" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.CH3OH\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Introduction\n", + "\n", + "This example demonstrates a simulation of methanol synthesis from hydrogen and carbon monoxide. Each methanol flowsheet module includes several built-in methods. This notebook demonstrates building the flowsheet, implementing model scaling, initialization and solving a square problem, costing and final constrained optimization.\n", + "\n", + "The ```build_model()``` method creates the Pyomo concrete model and builds the flowsheet by importing thermophysical and reaction properties and unit models and defining stream connections between these units. This method also implements appropriate default scaling on state and property variables.\n", + "\n", + "The ```set_inputs()``` method adds the appropriate initial specifications on the feed streams and unit operations. Specifications upstream of the reactor largely remain fixed throughout the optimization.\n", + "\n", + "The ```scale_flowsheet()``` method implements generic variable, unit model state variable, unit model constraint and Arc equality constraint scaling via IDAES scaling tools. Scaling factors are hard-coded in the flowsheet scripts to adjust for order of magnitude factors in appropriate constraints and simplify numerical solver calculations.\n", + "\n", + "The ```initialize_flowsheet()``` method uses the initial guess to initialize the models sequentially, solving each unit and propagating the results to the outlet stream to converge the next unit more quickly. This occurs just before the flowsheet-level solver call.\n", + "\n", + "The ```add_costing()``` method creates new variables and constraints related to unit model capital cost and operating cost calculations, and defines an objective function for the process economics. This method is called after the flowsheet-level solver call, and the flowsheet is resolved once costing is added. Capital costs are estimated using built-in costing methods within IDAES, and operating costs are estimated from a combination of known cost coefficients and surrogate models.\n", + "\n", + "The ```report()``` method displays relevant model results after the flowsheet has been fully solved." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2. Problem Statement \n", + "\n", + "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", + "\n", + "## 2.1. Main Inputs: \n", + "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", + "- Pre-reactor compressor outlet pressure (Pa)\n", + "- Pre-reactor heater outlet temperature (K)\n", + "\n", + "## 2.2. Main Outputs:\n", + "- Extent of reaction (mol/s)\n", + "- Reactor duty (W)\n", + "- Turbine duty (W)\n", + "- Methanol recovery (%)\n", + "- Annual revenue (USD/year)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:04.649464300Z", + "start_time": "2026-02-20T21:01:04.632133500Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet.png\")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 3. Import and Solve Flowsheet\n", + "## 3.1 Import Pyomo and IDAES Libraries" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's import the relevant Pyomo and IDAES Libraries:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:07.389407500Z", + "start_time": "2026-02-20T21:01:04.652988700Z" + } + }, + "outputs": [], + "source": [ + "import pytest\n", + "import os\n", + "\n", + "# Import Pyomo libraries\n", + "from pyomo.environ import (\n", + " Constraint,\n", + " Objective,\n", + " Var,\n", + " Expression,\n", + " Param,\n", + " ConcreteModel,\n", + " TransformationFactory,\n", + " value,\n", + " maximize,\n", + " units as pyunits,\n", + ")\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.network import Arc\n", + "\n", + "# Import IDAES core libraries\n", + "from idaes.core import FlowsheetBlock\n", + "from idaes.core.solvers import get_solver\n", + "from idaes.core.util import scaling as iscale\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "from idaes.core.util.initialization import propagate_state\n", + "\n", + "# Import required property modules\n", + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "\n", + "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", + "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", + "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", + "\n", + "from idaes.models.unit_models import (\n", + " Feed,\n", + " Mixer,\n", + " Heater,\n", + " Compressor,\n", + " Turbine,\n", + " StoichiometricReactor,\n", + " Flash,\n", + " Product,\n", + ")\n", + "from idaes.models.unit_models.mixer import MomentumMixingType\n", + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core import UnitModelCostingBlock\n", + "from idaes.models.costing.SSLW import SSLWCosting\n", + "\n", + "# import flowsheet functions\n", + "from methanol_flowsheet import (\n", + " build_model,\n", + " set_inputs,\n", + " scale_flowsheet,\n", + " initialize_flowsheet,\n", + " add_costing,\n", + " report,\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3.2 Build and Solve Flowsheet\n", + "The methanol flowsheet methods are called sequentially below, following the workflow contained in the ```main()``` method in `methanol_flowsheet.py`. First, let's set the solver options. IDAES contains a default solver `get_solver` which calls IPOPT using standard settings, and we set an iteration cap of 100 to catch nonconverging solver runs." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:07.399593900Z", + "start_time": "2026-02-20T21:01:07.390910200Z" + } + }, + "outputs": [], + "source": [ + "# Set solver options\n", + "solver = get_solver() # IPOPT\n", + "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", + "solver.options = optarg" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will build and solve the initial flowsheet using imported flowsheet methods - see `methanol_flowsheet.py` for complete method scripts.\n", + "\n", + "In the code below, we first define a Pyomo model object and build the model by defining each unit block with relevant property packages. As mentioned earlier, only the Flash unit (and the liquid outlet Product block) employ the VLE property package to ensure fast convergence of vapor-only processes.\n", + "\n", + "The process inputs are set for stoichiometric hydrogen and carbon monoxide feeds according to the process diagram in section 2.2. In the output below, the script returns the expected degrees of freedom for the model for each unit (compressor pressure change, heater duty, reactor duty and conversion, turbine pressure change and efficiency, cooler duty and flash duty and pressure change) and the actual model degrees of freedom before input specification, after the feed inputs are specified (flow, enthalpy, pressure, and composition for each feed) and after the unit model inputs are specified.\n", + "\n", + "After setting process inputs, we have a square problem for initialization. Here, we first implement IDAES scaling tools to create a more tractable problem during the solve step, and then sequentially initialize and propagate results from each unit block. As expected, the model only performs dew and bubble point calculations for the Flash and CH3OH product blocks where liquid phases are present and we obtain a square, solved problem:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Final DOF = 0\n", - "DOF before solve: 0\n", - "\n", - "Solving initial problem...\n" - ] + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.234663Z", + "start_time": "2026-02-20T21:01:07.401096600Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unit degrees of freedom\n", + "M101 0\n", + "C101 1\n", + "H101 1\n", + "R101 2\n", + "T101 2\n", + "H102 1\n", + "F101 2\n", + "Total DOF: 23\n", + "DOF after streams specified: 9\n", + "DOF after units specified: 0\n", + "\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n", + "DOF before solve: 0\n", + "\n", + "Solving initial problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 955\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 607\n", + "\n", + "Total number of variables............................: 310\n", + " variables with only lower bounds: 35\n", + " variables with lower and upper bounds: 258\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 310\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 2.79e+02 2.77e+00 -1.0 1.00e-02 - 9.90e-01 9.90e-01h 1\n", + " 2 0.0000000e+00 2.77e+00 1.21e+00 -1.0 1.00e-04 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 9.31e-10 0.00e+00 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 1.1368683772161603e-13 9.3132257461547852e-10\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 1.1368683772161603e-13 9.3132257461547852e-10\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total seconds in IPOPT = 0.003\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Build and solve flowsheet\n", + "m = ConcreteModel()\n", + "build_model(m) # build flowsheet by adding unit models and property packages\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "\n", + "results = solver.solve(m, tee=True) # initial square problem solve" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3.3 Flowsheet Costing and Optimization\n", + "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs. Additional, we calculate reactor operating costs as a function of conversion and assume constant rates for electricity, heating and cooling costs. Capital costs are annualized over 15 years, and revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, including a check on the reaction stoichiometry, relevant duty and state variable values, economic results, and stream tables for feed and product streams:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.373826200Z", + "start_time": "2026-02-20T21:01:09.242152800Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving with costing...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 971\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 611\n", + "\n", + "Total number of variables............................: 319\n", + " variables with only lower bounds: 43\n", + " variables with lower and upper bounds: 258\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 319\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8492051e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.9068962e+07 5.76e+04 6.45e+01 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", + " 2 -2.9074767e+07 5.71e+02 9.98e+00 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", + " 3 -2.9074825e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9074825e+07 1.63e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9074825e+07 1.16e-09 9.87e-08 -1.0 2.66e-08 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 5\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -4.4948186430824109e+01 -2.9074824816033181e+07\n", + "Dual infeasibility......: 9.8709848486689587e-08 6.3850664070387003e-02\n", + "Constraint violation....: 4.5474735088646412e-12 1.1641532182693481e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.8709848486689587e-08 6.3850664070387003e-02\n", + "\n", + "\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 6\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Initial solution process results:\n", + "\n", + "\n", + "Extent of reaction: 237.60047790000004\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.75\n", + "Reactor duty (MW): -45.21917830318437\n", + "Duty from Reaction (MW)): 21.536107316856004\n", + "Turbine work (MW): -0.9593346445867349\n", + "Mixer outlet temperature (C)): 20.0517142137536\n", + "Compressor outlet temperature (C)): 20.05171421375354\n", + "Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 234.0\n", + "Turbine outlet temperature (C)): 192.87815244243325\n", + "Turbine outlet pressure (Pa)): 3100000.0\n", + "Cooler outlet temperature (C)): 134.0\n", + "Flash outlet temperature (C)): 134.0\n", + "Methanol recovery(%): 60.00443012921678\n", + "annualized capital cost ($/year) = 219790.50447043462\n", + "operating cost ($/year) = 380701687.4964803\n", + "sales ($/year) = 64685201172.198105\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 29074824.816033185\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 336.23\n", + " Total Mole Fraction CH4 dimensionless 2.8373e-06\n", + " Total Mole Fraction CO dimensionless 0.23555\n", + " Total Mole Fraction H2 dimensionless 0.48181\n", + " Total Mole Fraction CH3OH dimensionless 0.28263\n", + " Molar Enthalpy joule / mole -80218.\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 142.57\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3813e+05\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "print(\"Solving with costing...\")\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1211\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 768\n", - "\n", - "Total number of variables............................: 397\n", - " variables with only lower bounds: 41\n", - " variables with lower and upper bounds: 336\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 397\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 2.79e+02 4.22e+03 -1.0 1.96e+03 - 9.90e-01 9.90e-01h 1\n", - " 2 0.0000000e+00 2.77e+00 3.86e+03 -1.0 2.03e+01 - 9.90e-01 9.90e-01h 1\n", - " 3 0.0000000e+00 7.44e-06 1.01e+03 -1.0 2.01e-01 - 9.90e-01 1.00e+00h 1\n", - "Cannot recompute multipliers for feasibility problem. Error in eq_mult_calculator\n", - "\n", - "Number of Iterations....: 3\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 1.0099088928127792e+05 1.0099088928127792e+05\n", - "Constraint violation....: 2.4014227693119351e-10 7.4444105848670006e-06\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 2.4014227693119351e-10 1.0099088928127792e+05\n", - "\n", - "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.005\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - } - ], - "source": [ - "# Build and solve flowsheet\n", - "solver = get_solver() # IPOPT\n", - "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", - "solver.options = optarg\n", - "\n", - "m = ConcreteModel() # create a new model so we may reference 'm' below\n", - "build_model(m) # build flowsheet\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "\n", - "# let the solver determine the tear stream\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "results = solver.solve(m, tee=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.3 Flowsheet Costing and Optimization\n", - "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs, reactor operating costs and utility costs for heating, cooling and electricity. As before, revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, which are updated for new results with the presence of a recycle stream:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:17.672850500Z", - "start_time": "2026-02-20T21:01:17.493149400Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:19.342021Z", - "iopub.status.busy": "2026-02-20T21:02:19.342021Z", - "iopub.status.idle": "2026-02-20T21:02:19.476954Z", - "shell.execute_reply": "2026-02-20T21:02:19.476954Z" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" + ] }, - "scrolled": false - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.500156800Z", + "start_time": "2026-02-20T21:01:09.382424800Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving optimization problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 975\n", + "Number of nonzeros in inequality constraint Jacobian.: 8\n", + "Number of nonzeros in Lagrangian Hessian.............: 613\n", + "\n", + "Total number of variables............................: 322\n", + " variables with only lower bounds: 43\n", + " variables with lower and upper bounds: 259\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 318\n", + "Total number of inequality constraints...............: 8\n", + " inequality constraints with only lower bounds: 4\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 4\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8492012e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.8402807e+07 2.72e+04 9.71e+01 -1.0 8.82e+06 - 4.99e-02 2.59e-02h 1\n", + " 2 -2.8406592e+07 2.70e+04 9.55e+01 -1.0 8.56e+06 - 7.51e-02 8.58e-03h 1\n", + " 3 -2.8493711e+07 2.29e+04 3.69e+02 -1.0 8.41e+06 - 1.67e-01 1.52e-01h 1\n", + " 4 -2.8493256e+07 2.28e+04 1.20e+04 -1.0 4.60e+06 - 1.00e-01 2.61e-03h 1\n", + " 5 -2.8504483e+07 2.24e+04 1.20e+04 -1.0 4.52e+06 - 2.44e-02 2.38e-02h 1\n", + " 6 -2.8536508e+07 2.16e+04 2.28e+04 -1.0 4.39e+06 - 5.48e-02 6.86e-02h 1\n", + " 7 -2.8537589e+07 2.16e+04 1.35e+05 -1.0 3.94e+06 - 2.56e-01 2.49e-03h 1\n", + " 8 -2.8537637e+07 2.15e+04 6.77e+06 -1.0 1.30e+06 - 4.68e-01 1.17e-04h 1\n", + " 9 -2.8910081e+07 8.51e+04 2.07e+06 -1.0 1.31e+06 - 4.38e-01 9.05e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -2.8914165e+07 7.59e+04 7.45e+06 -1.0 9.51e+04 - 9.00e-01 1.08e-01h 1\n", + " 11 -2.8947367e+07 1.17e+03 1.82e+05 -1.0 8.76e+04 - 9.09e-01 9.90e-01h 1\n", + " 12 -2.8953051e+07 1.08e+01 5.44e+06 -1.0 1.43e+03 -4.0 3.59e-02 9.92e-01h 1\n", + " 13 -2.8953104e+07 4.13e-04 1.09e+05 -1.0 2.11e+01 -4.5 9.90e-01 1.00e+00h 1\n", + " 14 -2.8953015e+07 2.97e-05 8.41e+04 -1.0 3.36e+01 -5.0 9.90e-01 1.00e+00f 1\n", + " 15 -2.8952945e+07 9.83e-05 7.75e+02 -1.0 6.25e+01 -5.4 9.91e-01 1.00e+00f 1\n", + " 16 -2.8952999e+07 1.24e-05 4.07e+00 -1.7 2.92e+01 -5.9 1.00e+00 1.00e+00f 1\n", + " 17 -2.8953295e+07 1.59e-05 3.08e+04 -3.8 1.68e+01 -6.4 9.84e-01 1.00e+00f 1\n", + " 18 -6.7235329e+07 3.98e+05 3.08e+04 -3.8 3.24e+06 - 6.31e-04 1.00e+00f 1\n", + " 19 -6.7161096e+07 3.96e+05 3.08e+04 -3.8 3.97e+05 -6.9 4.51e-04 6.00e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r-6.7161096e+07 3.96e+05 1.00e+03 1.1 0.00e+00 -7.3 0.00e+00 3.70e-07R 5\n", + " 21r-6.0126088e+07 1.13e+05 9.98e+02 1.1 9.47e+08 - 7.54e-04 8.89e-04f 1\n", + " 22 -5.8571015e+07 9.76e+04 1.26e+02 -3.8 1.33e+06 - 2.10e-01 1.37e-01h 1\n", + " 23 -5.8570701e+07 9.76e+04 4.63e+04 -3.8 1.17e+06 - 5.53e-01 3.23e-05h 1\n", + " 24 -5.8606170e+07 8.79e+04 1.84e+05 -3.8 2.62e+06 - 5.56e-03 9.99e-02h 1\n", + " 25 -5.8612488e+07 8.60e+04 7.19e+05 -3.8 2.49e+06 - 2.94e-01 2.08e-02h 1\n", + " 26 -5.8740061e+07 4.93e+04 1.28e+05 -3.8 2.43e+06 - 1.96e-01 4.35e-01h 1\n", + " 27 -5.8740292e+07 4.91e+04 3.28e+07 -3.8 9.94e+05 - 6.54e-01 4.63e-03h 1\n", + " 28 -5.8788497e+07 5.30e+03 1.02e+07 -3.8 9.26e+05 - 8.88e-01 1.00e+00h 1\n", + " 29 -5.8643006e+07 5.29e+03 1.65e+07 -3.8 2.35e+07 - 9.21e-04 1.55e-03h 7\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30 -5.7470132e+07 2.03e+02 1.15e+09 -3.8 2.85e+05 - 9.22e-06 1.00e+00h 1\n", + " 31 -5.7582403e+07 9.77e+00 1.14e+08 -3.8 1.63e+04 - 9.98e-01 1.00e+00h 1\n", + " 32 -7.8527164e+07 1.13e+05 8.45e+06 -3.8 4.35e+06 - 4.64e-01 9.37e-01f 1\n", + " 33 -7.8529326e+07 1.13e+05 8.45e+06 -3.8 5.31e+06 - 7.75e-01 1.16e-04h 1\n", + " 34 -7.9550162e+07 1.33e+05 6.60e+06 -3.8 4.19e+06 - 8.67e-01 2.18e-01h 1\n", + " 35 -7.9541163e+07 1.33e+05 6.57e+06 -3.8 3.58e+05 - 1.65e-03 4.97e-03h 1\n", + " 36 -7.9533059e+07 1.32e+05 6.54e+06 -3.8 1.15e+05 -7.8 1.26e-06 4.40e-03h 1\n", + " 37 -7.9485981e+07 1.29e+05 6.39e+06 -3.8 6.04e+04 -8.3 9.51e-01 2.34e-02h 1\n", + " 38 -7.8379026e+07 4.89e+04 2.42e+06 -3.8 1.52e+05 - 6.47e-01 6.21e-01h 1\n", + " 39 -7.8367473e+07 4.80e+04 2.38e+06 -3.8 5.52e+04 -8.8 3.60e-03 1.70e-02h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 -7.7618174e+07 1.40e+02 3.78e+03 -3.8 3.11e+04 -9.2 1.00e+00 1.00e+00h 1\n", + " 41 -7.7621799e+07 9.06e-01 7.63e-02 -3.8 4.67e+03 - 1.00e+00 1.00e+00h 1\n", + " 42 -7.7699327e+07 1.63e+02 9.22e-03 -3.8 6.11e+04 - 1.00e+00 1.00e+00f 1\n", + " 43 -7.7700167e+07 4.77e-02 2.09e-06 -3.8 1.01e+04 - 1.00e+00 1.00e+00h 1\n", + " 44 -7.7700500e+07 3.88e+00 3.43e+02 -5.7 9.57e+04 - 9.77e-01 1.00e+00h 1\n", + " 45 -7.7700531e+07 4.16e-01 1.40e-03 -5.7 2.26e+04 - 1.00e+00 9.06e-01h 1\n", + " 46 -7.7700531e+07 5.03e-04 3.89e-08 -5.7 9.81e+02 - 1.00e+00 1.00e+00f 1\n", + " 47 -7.7700536e+07 9.48e-04 2.13e-01 -8.6 1.62e+03 - 1.00e+00 9.99e-01h 1\n", + " 48 -7.7700536e+07 5.82e-09 1.08e-10 -8.6 1.88e+00 - 1.00e+00 1.00e+00f 1\n", + " 49 -7.7700536e+07 9.31e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 49\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -1.2012103932708935e+02 -7.7700535938862920e+07\n", + "Dual infeasibility......: 6.9703019509761989e-11 4.5087538392986020e-05\n", + "Constraint violation....: 1.0186340659856796e-10 9.3132257461547852e-09\n", + "Variable bound violation: 5.1274423640279565e-06 5.1274423640279565e-06\n", + "Complementarity.........: 1.4074777602003514e-11 9.1042982063954507e-06\n", + "Overall NLP error.......: 1.0186340659856796e-10 4.5087538392986020e-05\n", + "\n", + "\n", + "Number of objective function evaluations = 63\n", + "Number of objective gradient evaluations = 50\n", + "Number of equality constraint evaluations = 63\n", + "Number of inequality constraint evaluations = 63\n", + "Number of equality constraint Jacobian evaluations = 51\n", + "Number of inequality constraint Jacobian evaluations = 51\n", + "Number of Lagrangian Hessian evaluations = 49\n", + "Total seconds in IPOPT = 0.048\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Optimal solution process results:\n", + "\n", + "\n", + "Extent of reaction: 269.280544787992\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.8500000099999546\n", + "Reactor duty (MW): -51.36357357754579\n", + "Duty from Reaction (MW)): 24.407588579583596\n", + "Turbine work (MW): -1.9904899177794853\n", + "Mixer outlet temperature (C)): 20.05171421375337\n", + "Compressor outlet temperature (C)): 20.051714213753485\n", + "Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 231.85000468716584\n", + "Turbine outlet temperature (C)): 139.85888172675567\n", + "Turbine outlet pressure (Pa)): 1427653.3547820917\n", + "Cooler outlet temperature (C)): 52.56999709299214\n", + "Flash outlet temperature (C)): 134.0\n", + "Methanol recovery(%): 92.80355474657543\n", + "annualized capital cost ($/year) = 235547.18924473305\n", + "operating cost ($/year) = 451663512.6847631\n", + "sales ($/year) = 113381889876.90088\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 77700535.9388629\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 165.54\n", + " Total Mole Fraction CH4 dimensionless 5.7630e-06\n", + " Total Mole Fraction CO dimensionless 0.28706\n", + " Total Mole Fraction H2 dimensionless 0.59587\n", + " Total Mole Fraction CH3OH dimensionless 0.11706\n", + " Molar Enthalpy joule / mole -52313.\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 249.90\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3792e+05\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "opt_res = solver.solve(m, tee=True)\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, the process achieves a much greater revenue as a result of increasing conversion and lowering the inlet temperature to the Flash unit to encourage methanol recovery in the liquid phase. The results show a slight increase in equipment and operating costs from these changes, as well as a small loss of methanol in the exhaust." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1227\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 772\n", - "\n", - "Total number of variables............................: 406\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 336\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 406\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8497869e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.9074832e+07 5.76e+04 4.22e+03 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", - " 2 -2.9080637e+07 5.71e+02 3.82e+03 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", - " 3 -2.9080695e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9080695e+07 9.31e-10 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 4\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -4.4953175283791907e+01 -2.9080695361147854e+07\n", - "Dual infeasibility......: 2.4946824403693549e-06 1.6138370562967401e+00\n", - "Constraint violation....: 4.5474735088646412e-12 9.3132257461547852e-10\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 1.6138370562967401e+00\n", - "\n", - "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.006\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 4. Problem Statement - Analyzing Benefit of Recycling Flash Vapor\n", + "\n", + "To increase the efficiency of the process as well as overall methanol production and revenue, we can add a recycle stream to send most of the Flash vapor back to the start of the process. This will reduce methanol loss in the exhaust and increase feed utilization, resulting in increased operating costs and increased production (revenue) at the same conversion. Note that for conversions less than 100%, a simulation with no purge will never converge due to accumulation of gases within the system. Therefore, to ensure we close the mass balance we set a lower bound at 10% purge from the Flash vapor to the exhaust. We expect to see a marginal increase in operating costs due to increased flow, and a much larger increase in overall production resulting in a higher total revenue.\n", + "\n", + "By adding a recycle to the flowsheet, we significantly decrease the tractability of the problem and require a better initial guess. The SequentialDecomposition algorithm automatically determines a stream to *tear*, or use to break the solve loop, and iterates from a set of user-supplied initial guesses until converging on the optimal solution. The code below calls an initialization method to automatically determine the tear stream. See the initialization method of `methanol_flowsheet_w_recycle.py` for further details Sequential Decomposition scheme.\n", + "\n", + "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", + "\n", + "## 4.1. Main Inputs: \n", + "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", + "- Pre-reactor compressor outlet pressure (Pa)\n", + "- Pre-reactor heater outlet temperature (K)\n", + "\n", + "## 4.2. Main Outputs:\n", + "- Extent of reaction (mol/s)\n", + "- Reactor duty (W)\n", + "- Compressor duty (W)\n", + "- Turbine duty (W)\n", + "- Methanol recovery (%)\n", + "- Purge percentage (%)\n", + "- Annual revenue (USD/year)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initial solution process results:\n", - "\n", - "\n", - "Extent of reaction: 237.6064180604515\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.22029794711382\n", - "Duty from Reaction (MW)): 21.536645732999325\n", - "Compressor work (MW): -2.5668711294294714e-15\n", - "Turbine work (MW): -0.959378502391431\n", - "Feed Mixer outlet temperature (C)): 20.051714213753144\n", - "Recycle Mixer outlet temperature (C)): 20.056485612776214\n", - "Feed Compressor outlet temperature (C)): 20.0564856127761\n", - "Feed Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.87840947667888\n", - "Turbine outlet pressure (Pa)): 3100000.0\n", - "Cooler outlet temperature (C)): 134.0\n", - "Flash outlet temperature (C)): 134.0\n", - "Purge percentage (amount of vapor vented to exhaust): 99.99 %\n", - "Methanol recovery(%): 60.005984934911716\n", - "annualized capital cost ($/year) = 219794.2325658716\n", - "operating cost ($/year) = 380711692.18369955\n", - "sales ($/year) = 64691081725.72807\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29080695.36114784\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 336.21\n", - " Total Mole Fraction CH4 dimensionless 2.8375e-06\n", - " Total Mole Fraction CO dimensionless 0.23555\n", - " Total Mole Fraction H2 dimensionless 0.48181\n", - " Total Mole Fraction CH3OH dimensionless 0.28263\n", - " Molar Enthalpy joule / mole -80218.\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 142.58\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3813e+05\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions, including a purge between 10-50% of flash vapor. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:18.109467400Z", - "start_time": "2026-02-20T21:01:17.672850500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:19.478988Z", - "iopub.status.busy": "2026-02-20T21:02:19.478988Z", - "iopub.status.idle": "2026-02-20T21:02:19.773886Z", - "shell.execute_reply": "2026-02-20T21:02:19.773886Z" + "cell_type": "code", + "execution_count": 11, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.517374100Z", + "start_time": "2026-02-20T21:01:09.509320Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet_recycle.png\")" + ] }, - "scrolled": false - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 5. Import and Solve Recycle Flowsheet\n", + "## 5.1 Import Pyomo and IDAES Libraries\n", + "As we are rebuilding the model, we need to import require Pyomo and IDAES libraries:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving optimization problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 12, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.534388600Z", + "start_time": "2026-02-20T21:01:09.517374100Z" + } + }, + "outputs": [], + "source": [ + "import pytest\n", + "import os\n", + "\n", + "# Import Pyomo libraries\n", + "from pyomo.environ import (\n", + " Constraint,\n", + " Objective,\n", + " Var,\n", + " Expression,\n", + " Param,\n", + " ConcreteModel,\n", + " TransformationFactory,\n", + " value,\n", + " maximize,\n", + " units as pyunits,\n", + ")\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.network import Arc, SequentialDecomposition\n", + "\n", + "# Import IDAES core libraries\n", + "from idaes.core import FlowsheetBlock\n", + "from idaes.core.solvers import get_solver\n", + "from idaes.core.util import scaling as iscale\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "from idaes.core.util.initialization import propagate_state\n", + "\n", + "# Import required models\n", + "\n", + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "\n", + "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", + "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", + "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", + "\n", + "from idaes.models.unit_models import (\n", + " Feed,\n", + " Mixer,\n", + " Heater,\n", + " Compressor,\n", + " Turbine,\n", + " StoichiometricReactor,\n", + " Flash,\n", + " Separator as Splitter,\n", + " Product,\n", + ")\n", + "from idaes.models.unit_models.mixer import MomentumMixingType\n", + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core import UnitModelCostingBlock\n", + "from idaes.models.costing.SSLW import SSLWCosting\n", + "import idaes.logger as idaeslog\n", + "\n", + "# import flowsheet functions\n", + "from methanol_flowsheet_w_recycle import (\n", + " build_model,\n", + " set_inputs,\n", + " scale_flowsheet,\n", + " initialize_flowsheet,\n", + " add_costing,\n", + " report,\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5.2 Build and Solve Recycle Flowsheet\n", + "As before, we will first build the flowsheet, set required inputs, initialize and solve a square problem. Recycling methanol to pre-reactor blocks complicates VLE calculations, and limiting VLE calculations to the Flash unit and liquid Product block greatly increases tractability during initialization. All initial feed and unit specifications are identical to the non-recycle case; the Sequential Decomposition algorithm automatically selects the compressor feed as the tear stream and uses \"no recycle\" results as a first guess. In the output below, the solver solves all units and then resolves select blocks with updated inlet results, followed by a full flowsheet solve:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1236\n", - "Number of nonzeros in inequality constraint Jacobian.: 10\n", - "Number of nonzeros in Lagrangian Hessian.............: 779\n", - "\n", - "Total number of variables............................: 410\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 337\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 405\n", - "Total number of inequality constraints...............: 10\n", - " inequality constraints with only lower bounds: 5\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 5\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8497829e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.8431127e+07 2.74e+04 9.77e+01 -1.0 8.82e+06 - 4.99e-02 1.94e-02h 1\n", - " 2 -2.8430719e+07 2.74e+04 7.81e+02 -1.0 8.52e+06 - 3.76e-02 1.99e-04h 1\n", - " 3 -2.8524903e+07 2.48e+04 1.61e+05 -1.0 6.46e+06 - 2.49e-04 9.25e-02f 1\n", - " 4 -2.8526723e+07 2.48e+04 1.61e+05 -1.0 5.76e+06 - 5.84e-02 9.84e-04h 1\n", - " 5 -2.8554206e+07 2.48e+04 1.60e+05 -1.0 1.49e+07 - 3.32e-03 8.96e-04h 1\n", - " 6 -2.9123967e+07 2.43e+04 1.52e+05 -1.0 1.49e+07 - 1.23e-01 1.84e-02f 1\n", - " 7 -2.9208690e+07 2.43e+04 1.51e+05 -1.0 9.71e+06 - 2.32e-02 2.78e-03h 1\n", - " 8 -3.0003175e+07 2.36e+04 1.08e+06 -1.0 9.31e+06 - 1.92e-01 2.61e-02h 1\n", - " 9 -3.1468200e+07 2.25e+04 1.09e+06 -1.0 8.71e+06 - 6.69e-02 4.91e-02f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -3.1583903e+07 2.24e+04 1.14e+07 -1.0 5.51e+06 - 3.91e-01 3.89e-03h 1\n", - " 11 -4.3112078e+07 3.08e+04 5.71e+06 -1.0 5.49e+06 - 1.57e-01 3.86e-01f 1\n", - " 12 -4.3711661e+07 4.53e+04 5.09e+06 -1.0 3.67e+06 - 8.46e-02 2.88e-02h 1\n", - " 13 -4.3718221e+07 4.53e+04 1.94e+06 -1.0 3.57e+06 - 5.81e-01 3.23e-04h 1\n", - " 14 -4.3760623e+07 4.51e+04 4.16e+07 -1.0 3.56e+06 - 4.25e-01 5.93e-03h 1\n", - " 15 -4.4646398e+07 7.99e+04 5.37e+07 -1.0 3.54e+06 - 6.75e-01 1.23e-01h 4\n", - " 16 -6.6613749e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", - " 17 -6.5999969e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", - " 18 -6.5249518e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", - " 19 -6.4064695e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -6.4051103e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", - " 21 -6.5080976e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", - " 22 -7.5335243e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", - " 23 -7.4658996e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", - " 24 -7.4649764e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", - " 25 -7.4613845e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", - " 26 -7.4421363e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", - " 27 -7.4390154e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n" - ] + "cell_type": "code", + "execution_count": 13, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.393968500Z", + "start_time": "2026-02-20T21:01:09.535877100Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unit degrees of freedom\n", + "M101 0\n", + "C101 1\n", + "H101 1\n", + "R101 2\n", + "T101 2\n", + "H102 1\n", + "F101 2\n", + "M102 0\n", + "S101 1\n", + "Total DOF: 24\n", + "DOF after streams specified: 10\n", + "DOF after units specified: 0\n", + "\n", + "Tear Stream:\n", + "fs.s02 : fs.M102.outlet to fs.C101.inlet\n", + "\n", + "Calculation order:\n", + "fs.H2\n", + "fs.M101\n", + "fs.R101\n", + "fs.T101\n", + "fs.H102\n", + "fs.F101\n", + "fs.S101\n", + "fs.EXHAUST\n", + "\n", + "Initial DOF = 0\n", + "Solving fs.H2\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CO\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.C101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.R101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.T101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H102\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.F101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.S101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CH3OH\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.EXHAUST\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M102\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H2\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CO\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.EXHAUST\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CH3OH\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Final DOF = 0\n", + "DOF before solve: 0\n", + "\n", + "Solving initial problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1211\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 768\n", + "\n", + "Total number of variables............................: 397\n", + " variables with only lower bounds: 41\n", + " variables with lower and upper bounds: 336\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 397\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 2.79e+02 4.22e+03 -1.0 1.96e+03 - 9.90e-01 9.90e-01h 1\n", + " 2 0.0000000e+00 2.77e+00 3.86e+03 -1.0 2.03e+01 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 7.44e-06 1.01e+03 -1.0 2.01e-01 - 9.90e-01 1.00e+00h 1\n", + " 4 0.0000000e+00 2.10e-09 9.89e+04 -1.0 1.19e-07 - 9.90e-01 1.00e+00h 1\n", + " 5 0.0000000e+00 2.10e-09 0.00e+00 -1.0 2.51e-08 - 9.91e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 5\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 6.7595993318865371e-14 2.0954757928848267e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 6.7595993318865371e-14 2.0954757928848267e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 6\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.009\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Build and solve flowsheet\n", + "solver = get_solver() # IPOPT\n", + "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", + "solver.options = optarg\n", + "\n", + "m = ConcreteModel() # create a new model so we may reference 'm' below\n", + "build_model(m) # build flowsheet\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "\n", + "# let the solver determine the tear stream\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "results = solver.solve(m, tee=True)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 28 -7.2740081e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", - " 29 -7.2726278e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.2726419e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", - " 31 -8.6665745e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", - " 32 -8.6649468e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", - " 33 -8.6148813e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.44e-02 1.00e+00h 1\n", - " 34 -8.6163785e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", - " 35 -8.6204319e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", - " 36 -8.6333114e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", - " 37 -8.6713987e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", - " 38 -8.7245785e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", - " 39 -9.0563354e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 40 -9.9476688e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", - " 41 -9.9478624e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", - " 42 -1.0299591e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", - " 43 -1.0299655e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", - " 44 -1.0436244e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", - " 45 -1.0441522e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", - " 46 -1.0438806e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", - " 47 -1.0435495e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", - " 48 -1.0426618e+08 2.01e+03 2.19e+01 -3.8 1.81e+06 - 1.20e-01 1.00e+00h 1\n", - " 49 -1.0426992e+08 2.91e+02 3.40e-01 -3.8 6.45e+04 -13.1 1.00e+00 9.64e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.80e+06 - 5.54e-03 2.57e-01h 1\n", - " 51 -1.0427055e+08 2.92e+02 3.97e+02 -3.8 3.24e+06 - 1.33e-01 1.97e-02h 1\n", - " 52 -1.0427008e+08 1.05e+02 1.15e+05 -3.8 2.71e+04 - 7.76e-04 1.00e+00f 1\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5.3 Flowsheet Costing and Optimization\n", + "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs, reactor operating costs and utility costs for heating, cooling and electricity. As before, revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, which are updated for new results with the presence of a recycle stream:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 53 -1.0427044e+08 9.41e+01 7.74e+04 -3.8 4.75e+04 -12.6 1.00e+00 3.26e-01h 2\n", - " 54 -1.0427081e+08 9.98e+01 6.24e+04 -3.8 8.03e+04 -13.1 1.00e+00 1.91e-01h 2\n", - " 55 -1.0427080e+08 8.21e-01 1.24e+00 -3.8 7.52e+04 - 1.00e+00 1.00e+00h 1\n", - " 56 -1.0427114e+08 2.09e+01 2.34e+02 -3.8 3.16e+04 -12.7 1.00e+00 4.65e-01h 2\n", - " 57 -1.0427107e+08 4.98e-01 5.37e+00 -3.8 1.61e+04 - 1.00e+00 1.00e+00h 1\n", - " 58 -1.0427121e+08 3.58e+00 1.04e+03 -3.8 1.22e+04 -12.3 1.00e+00 4.79e-01h 2\n", - " 59 -1.0427120e+08 8.56e-03 3.90e+00 -3.8 1.47e+03 - 1.00e+00 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 60 -1.0427265e+08 3.69e+02 2.06e+03 -3.8 6.13e+04 -12.7 1.00e+00 1.00e+00f 1\n", - " 61 -1.0427267e+08 8.82e-03 8.41e-01 -3.8 2.14e+04 - 1.00e+00 1.00e+00h 1\n", - " 62 -1.0427488e+08 8.81e+02 4.71e+03 -3.8 9.30e+04 -13.2 9.57e-01 1.00e+00h 1\n", - " 63 -1.0427489e+08 1.12e-02 8.43e+03 -3.8 2.41e+04 - 4.26e-01 1.00e+00h 1\n", - " 64 -1.0427588e+08 1.77e+02 2.25e+02 -3.8 4.16e+04 -12.8 1.00e+00 1.00e+00h 1\n", - " 65 -1.0427569e+08 7.17e+00 2.18e+02 -3.8 9.45e+03 - 8.56e-01 1.00e+00h 1\n", - " 66 -1.0427569e+08 3.81e-04 1.34e+03 -3.8 7.69e+02 - 3.56e-01 1.00e+00h 1\n", - " 67 -1.0427568e+08 5.99e-04 1.01e+02 -3.8 7.28e+01 - 6.32e-01 1.00e+00h 1\n", - " 68 -1.0427568e+08 5.44e-04 1.32e+02 -3.8 6.86e+01 - 5.69e-01 1.00e+00h 1\n", - " 69 -1.0427569e+08 3.30e-03 2.05e+01 -3.8 2.50e+02 - 6.00e-01 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 70 -1.0427569e+08 1.33e-05 2.19e+01 -3.8 2.05e+02 - 5.83e-01 1.00e+00h 1\n", - " 71 -1.0427569e+08 1.09e-03 3.63e+00 -3.8 5.68e+02 - 5.94e-01 1.00e+00f 1\n", - " 72 -1.0427569e+08 6.75e-04 3.84e+00 -3.8 1.21e+03 - 5.81e-01 1.00e+00h 1\n", - " 73 -1.0427569e+08 6.52e-03 6.49e-01 -3.8 3.03e+03 - 5.80e-01 1.00e+00h 1\n", - " 74 -1.0427570e+08 3.77e-02 6.80e-01 -3.8 7.51e+03 - 5.69e-01 1.00e+00h 1\n", - " 75 -1.0427573e+08 2.57e-01 1.17e-01 -3.8 1.96e+04 - 5.45e-01 1.00e+00h 1\n", - " 76 -1.0427580e+08 2.17e+00 1.46e-01 -3.8 5.66e+04 - 4.91e-01 1.00e+00h 1\n", - " 77 -1.0427608e+08 3.10e+01 6.00e-02 -3.8 2.13e+05 - 3.77e-01 1.00e+00h 1\n", - " 78 -1.0427817e+08 1.76e+03 5.49e-01 -3.8 1.56e+06 - 1.85e-01 1.00e+00h 1\n", - " 79 -1.0427835e+08 1.67e+03 6.12e-01 -3.8 1.75e+06 - 9.50e-01 6.05e-02h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 80 -1.0427838e+08 3.76e-01 2.22e-04 -3.8 9.99e+04 - 1.00e+00 1.00e+00h 1\n", - " 81 -1.0427881e+08 2.24e+00 1.80e+02 -5.7 8.49e+04 - 9.88e-01 1.00e+00h 1\n", - " 82 -1.0427883e+08 9.31e-02 1.16e-03 -5.7 1.69e+04 - 1.00e+00 9.65e-01h 1\n", - " 83 -1.0427883e+08 1.60e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", - " 84 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", - " 85 -1.0427884e+08 5.59e-09 2.35e-13 -8.6 7.18e-01 - 1.00e+00 1.00e+00h 1\n", - " 86 -1.0427884e+08 2.79e-09 9.30e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 86\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -1.6119507851267775e+02 -1.0427883997848792e+08\n", - "Dual infeasibility......: 9.2995983076271742e-12 6.0160107413515216e-06\n", - "Constraint violation....: 1.0913936421275139e-10 2.7939677238464355e-09\n", - "Complementarity.........: 1.4067955341342552e-11 9.1007124870068398e-06\n", - "Overall NLP error.......: 1.0913936421275139e-10 9.1007124870068398e-06\n", - "\n", - "\n", - "Number of objective function evaluations = 118\n", - "Number of objective gradient evaluations = 87\n", - "Number of equality constraint evaluations = 118\n", - "Number of inequality constraint evaluations = 118\n", - "Number of equality constraint Jacobian evaluations = 87\n", - "Number of inequality constraint Jacobian evaluations = 87\n", - "Number of Lagrangian Hessian evaluations = 86\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.091\n", - "Total CPU secs in NLP function evaluations = 0.014\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "code", + "execution_count": 15, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.612557100Z", + "start_time": "2026-02-20T21:01:12.405029Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1227\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 772\n", + "\n", + "Total number of variables............................: 406\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 336\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 406\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8497869e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.9074832e+07 5.76e+04 4.22e+03 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", + " 2 -2.9080637e+07 5.71e+02 3.82e+03 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", + " 3 -2.9080695e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9080695e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9080695e+07 1.16e-09 9.85e+02 -1.0 2.19e-08 - 9.90e-01 1.00e+00h 1\n", + " 6 -2.9080695e+07 9.31e-10 7.17e+04 -1.7 1.59e-08 - 9.91e-01 1.00e+00h 1\n", + " 7 -2.9080695e+07 9.31e-10 2.00e-07 -1.7 2.11e-08 - 1.00e+00 1.00e+00h 1\n", + " 8 -2.9080695e+07 9.31e-10 1.01e-09 -5.7 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + " 9 -2.9080695e+07 9.31e-10 3.69e-13 -8.6 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -2.9080695e+07 9.31e-10 2.90e-13 -10.9 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 10\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -4.4953175283792277e+01 -2.9080695361147840e+07\n", + "Dual infeasibility......: 2.8986503540945592e-13 1.8751682695104163e-07\n", + "Constraint violation....: 4.5474735088646412e-12 9.3132257461547852e-10\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.4052801174098027e-11 9.0909090922898242e-06\n", + "Overall NLP error.......: 1.4052801174098027e-11 9.0909090922898242e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 11\n", + "Number of objective gradient evaluations = 11\n", + "Number of equality constraint evaluations = 11\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 11\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 10\n", + "Total seconds in IPOPT = 0.017\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Initial solution process results:\n", + "\n", + "\n", + "Extent of reaction: 237.60641806045152\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.75\n", + "Reactor duty (MW): -45.22029794711383\n", + "Duty from Reaction (MW)): 21.536645732999325\n", + "Compressor work (MW): -3.72291430867571e-35\n", + "Turbine work (MW): -0.9593785023914099\n", + "Feed Mixer outlet temperature (C)): 20.0517142137532\n", + "Recycle Mixer outlet temperature (C)): 20.056485612776157\n", + "Feed Compressor outlet temperature (C)): 20.056485612776157\n", + "Feed Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 234.0\n", + "Turbine outlet temperature (C)): 192.8784094766802\n", + "Turbine outlet pressure (Pa)): 3100000.0\n", + "Cooler outlet temperature (C)): 134.0\n", + "Flash outlet temperature (C)): 134.0\n", + "Purge percentage (amount of vapor vented to exhaust): 99.99 %\n", + "Methanol recovery(%): 60.0059849349117\n", + "annualized capital cost ($/year) = 219794.23256587266\n", + "operating cost ($/year) = 380711692.1836992\n", + "sales ($/year) = 64691081725.72806\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 29080695.361147825\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 336.21\n", + " Total Mole Fraction CH4 dimensionless 2.8375e-06\n", + " Total Mole Fraction CO dimensionless 0.23555\n", + " Total Mole Fraction H2 dimensionless 0.48181\n", + " Total Mole Fraction CH3OH dimensionless 0.28263\n", + " Molar Enthalpy joule / mole -80218.\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 142.58\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3813e+05\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions, including a purge between 10-50% of flash vapor. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:13.760944100Z", + "start_time": "2026-02-20T21:01:12.626378Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving optimization problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1236\n", + "Number of nonzeros in inequality constraint Jacobian.: 10\n", + "Number of nonzeros in Lagrangian Hessian.............: 779\n", + "\n", + "Total number of variables............................: 410\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 337\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 405\n", + "Total number of inequality constraints...............: 10\n", + " inequality constraints with only lower bounds: 5\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 5\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8497829e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.8431127e+07 2.74e+04 9.77e+01 -1.0 8.82e+06 - 4.99e-02 1.94e-02h 1\n", + " 2 -2.8430719e+07 2.74e+04 7.81e+02 -1.0 8.52e+06 - 3.76e-02 1.99e-04h 1\n", + " 3 -2.8524903e+07 2.48e+04 1.61e+05 -1.0 6.46e+06 - 2.49e-04 9.25e-02f 1\n", + " 4 -2.8526723e+07 2.48e+04 1.61e+05 -1.0 5.76e+06 - 5.84e-02 9.84e-04h 1\n", + " 5 -2.8554206e+07 2.48e+04 1.60e+05 -1.0 1.49e+07 - 3.32e-03 8.96e-04h 1\n", + " 6 -2.9123967e+07 2.43e+04 1.52e+05 -1.0 1.49e+07 - 1.23e-01 1.84e-02f 1\n", + " 7 -2.9208690e+07 2.43e+04 1.51e+05 -1.0 9.71e+06 - 2.32e-02 2.78e-03h 1\n", + " 8 -3.0003175e+07 2.36e+04 1.08e+06 -1.0 9.31e+06 - 1.92e-01 2.61e-02h 1\n", + " 9 -3.1468200e+07 2.25e+04 1.09e+06 -1.0 8.71e+06 - 6.69e-02 4.91e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -3.1583903e+07 2.24e+04 1.14e+07 -1.0 5.51e+06 - 3.91e-01 3.89e-03h 1\n", + " 11 -4.3112078e+07 3.08e+04 5.71e+06 -1.0 5.49e+06 - 1.57e-01 3.86e-01f 1\n", + " 12 -4.3711661e+07 4.53e+04 5.09e+06 -1.0 3.67e+06 - 8.46e-02 2.88e-02h 1\n", + " 13 -4.3718221e+07 4.53e+04 1.94e+06 -1.0 3.57e+06 - 5.81e-01 3.23e-04h 1\n", + " 14 -4.3760623e+07 4.51e+04 4.16e+07 -1.0 3.56e+06 - 4.25e-01 5.93e-03h 1\n", + " 15 -4.4646398e+07 7.99e+04 5.37e+07 -1.0 3.54e+06 - 6.75e-01 1.23e-01h 4\n", + " 16 -6.6613710e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", + " 17 -6.5999923e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", + " 18 -6.5249462e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", + " 19 -6.4064651e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 -6.4051060e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", + " 21 -6.5080931e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", + " 22 -7.5335226e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", + " 23 -7.4658976e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", + " 24 -7.4649744e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", + " 25 -7.4613824e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", + " 26 -7.4421345e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", + " 27 -7.4390136e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n", + " 28 -7.2740056e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", + " 29 -7.2726253e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30 -7.2726394e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", + " 31 -8.6665441e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", + " 32 -8.6649164e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", + " 33 -8.6148490e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.45e-02 1.00e+00h 1\n", + " 34 -8.6163461e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", + " 35 -8.6203995e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", + " 36 -8.6332790e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", + " 37 -8.6713663e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", + " 38 -8.7245413e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", + " 39 -9.0562979e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 -9.9476648e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", + " 41 -9.9478583e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", + " 42 -1.0299584e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", + " 43 -1.0299648e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", + " 44 -1.0436243e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", + " 45 -1.0441521e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", + " 46 -1.0438805e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", + " 47 -1.0435494e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", + " 48 -1.0426618e+08 2.01e+03 2.19e+01 -3.8 1.81e+06 - 1.20e-01 1.00e+00h 1\n", + " 49 -1.0426992e+08 2.91e+02 3.40e-01 -3.8 6.45e+04 -13.1 1.00e+00 9.64e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.79e+06 - 5.54e-03 2.58e-01h 1\n", + " 51 -1.0427055e+08 2.93e+02 3.98e+02 -3.8 3.24e+06 - 1.33e-01 1.93e-02h 1\n", + " 52 -1.0427009e+08 1.02e+02 1.15e+05 -3.8 2.79e+04 - 7.85e-04 1.00e+00f 1\n", + " 53 -1.0427045e+08 9.18e+01 7.72e+04 -3.8 4.68e+04 -12.6 1.00e+00 3.29e-01h 2\n", + " 54 -1.0427082e+08 9.84e+01 6.22e+04 -3.8 8.09e+04 -13.1 1.00e+00 1.92e-01h 2\n", + " 55 -1.0427081e+08 7.24e-01 1.18e+00 -3.8 7.63e+04 - 1.00e+00 1.00e+00h 1\n", + " 56 -1.0427115e+08 2.08e+01 2.49e+02 -3.8 3.14e+04 -12.7 1.00e+00 4.68e-01h 2\n", + " 57 -1.0427108e+08 6.33e-01 6.20e+00 -3.8 1.65e+04 - 1.00e+00 1.00e+00h 1\n", + " 58 -1.0427122e+08 3.69e+00 9.97e+02 -3.8 1.26e+04 -12.3 1.00e+00 4.66e-01h 2\n", + " 59 -1.0427122e+08 5.22e-05 1.89e-01 -3.8 1.65e+03 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60 -1.0428563e+08 3.80e+04 2.56e+04 -3.8 3.34e+06 - 7.06e-02 1.80e-01f 1\n", + " 61 -1.0428562e+08 3.78e+04 2.55e+04 -3.8 4.32e+05 - 2.18e-02 5.77e-03h 1\n", + " 62 -1.0428017e+08 3.77e+04 2.54e+04 -3.8 1.25e+07 -12.7 7.48e-05 2.34e-03h 9\n", + " 63 -1.0427440e+08 3.74e+04 2.52e+04 -3.8 3.76e+06 -12.3 5.74e-03 7.81e-03h 8\n", + " 64 -1.0427481e+08 3.74e+04 2.52e+04 -3.8 4.44e+05 -9.2 2.60e-01 1.25e-03h 1\n", + " 65 -1.0427459e+08 3.69e+04 2.49e+04 -3.8 4.18e+05 -9.7 3.22e-03 1.13e-02h 1\n", + " 66 -1.0427441e+08 3.69e+04 2.49e+04 -3.8 7.62e+08 -10.1 6.54e-09 7.13e-08f 11\n", + " 67 -1.0427290e+08 3.69e+04 2.49e+04 -3.8 8.98e+05 -9.7 1.79e-03 4.88e-04h 12\n", + " 68 -1.0427211e+08 3.69e+04 2.49e+04 -3.8 7.85e+05 -9.3 1.13e-03 4.88e-04h 12\n", + " 69 -1.0427200e+08 3.69e+04 2.49e+04 -3.8 1.16e+06 -9.8 2.41e-03 2.60e-05h 16\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70 -1.0427193e+08 3.69e+04 2.49e+04 -3.8 4.05e+05 -9.3 2.02e-01 2.35e-04h 5\n", + " 71 -1.0426925e+08 3.69e+04 2.49e+04 -3.8 1.03e+06 -9.8 6.63e-04 6.63e-04s 22\n", + " 72 -1.0425036e+08 3.57e+04 2.41e+04 -3.8 3.87e+05 -9.4 3.17e-02 3.17e-02s 22\n", + " 73 -1.0424520e+08 3.57e+04 2.41e+04 -3.8 1.58e+06 -9.9 9.56e-04 9.56e-04s 22\n", + " 74 -1.0421332e+08 3.51e+04 2.37e+04 -3.8 7.70e+05 -9.4 1.52e-02 1.52e-02s 22\n", + " 75 -1.0409397e+08 3.47e+04 2.34e+04 -3.8 2.08e+06 -9.9 1.36e-02 1.36e-02s 22\n", + " 76 -1.0387838e+08 2.73e+04 1.81e+04 -3.8 3.89e+05 -9.5 2.45e-01 2.45e-01s 22\n", + " 77 -1.0368499e+08 2.52e+04 1.67e+04 -3.8 5.49e+05 -10.0 8.21e-02 8.21e-02s 22\n", + " 78 -1.0298419e+08 2.17e+04 1.42e+04 -3.8 8.63e+05 -10.4 1.56e-01 1.56e-01s 22\n", + " 79 -1.0163132e+08 1.11e+04 6.55e+03 -3.8 5.27e+05 -10.9 6.20e-01 6.20e-01s 22\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80 -1.0194825e+08 1.09e+03 5.66e+02 -3.8 8.31e+04 -11.4 9.54e-01 9.54e-01s 22\n", + " 81 -1.0310109e+08 8.15e+02 4.00e+02 -3.8 5.53e+05 -11.9 2.90e-01 2.90e-01s 22\n", + " 82r-1.0310109e+08 8.15e+02 1.00e+03 -1.6 0.00e+00 -12.4 0.00e+00 0.00e+00R 1\n", + " 83r-1.0310498e+08 2.20e+02 3.18e+03 -1.6 1.50e+03 -4.0 2.25e-03 9.91e-04f 1\n", + " 84r-1.0303151e+08 8.00e+01 3.93e+03 -1.6 8.93e+06 - 3.97e-03 2.67e-03f 1\n", + " 85r-1.0297296e+08 3.79e+01 4.49e+03 -1.6 2.18e+06 - 9.30e-03 7.81e-03f 1\n", + " 86r-1.0295114e+08 8.32e+01 6.01e+03 -1.6 1.88e+06 - 2.57e-02 1.93e-02f 1\n", + " 87r-1.0295645e+08 6.88e+02 7.54e+03 -1.6 1.99e+06 - 6.81e-02 5.54e-02f 1\n", + " 88r-1.0295646e+08 5.58e+02 2.74e+04 -1.6 1.22e+02 -4.5 4.65e-01 1.86e-01f 1\n", + " 89r-1.0253465e+08 4.33e+02 1.34e+04 -1.6 4.11e+05 - 9.66e-01 2.98e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r-1.0417196e+08 5.86e+02 1.34e+04 -1.6 6.16e+06 - 3.39e-01 8.07e-02f 1\n", + " 91r-1.0366409e+08 6.25e+02 2.53e+03 -1.6 1.19e+05 - 2.93e-01 1.00e+00f 1\n", + " 92r-1.0364727e+08 2.09e+02 3.79e+02 -1.6 5.53e+01 -5.0 1.00e+00 6.66e-01h 1\n", + " 93r-1.0365950e+08 8.11e-03 1.47e+00 -1.6 6.58e+01 -5.4 1.00e+00 1.00e+00f 1\n", + " 94r-1.0367534e+08 2.57e-01 2.93e+03 -2.4 2.27e+02 -5.9 1.00e+00 8.08e-01f 1\n", + " 95r-1.0369165e+08 1.08e-01 3.47e+03 -2.4 2.04e+02 -6.4 1.00e+00 6.02e-01f 1\n", + " 96r-1.0369511e+08 2.28e-03 3.84e+00 -2.4 4.36e+01 -6.9 1.00e+00 1.00e+00f 1\n", + " 97r-1.0369311e+08 1.00e+03 1.22e+02 -2.4 1.53e+05 - 7.06e-01 1.00e+00f 1\n", + " 98r-1.0369133e+08 5.34e-02 6.47e-02 -2.4 6.89e+01 -7.3 1.00e+00 1.00e+00h 1\n", + " 99r-1.0364795e+08 1.01e+02 3.37e+02 -3.6 3.26e+04 - 6.54e-01 7.41e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r-1.0309823e+08 3.06e+01 6.46e+02 -3.6 1.67e+05 - 9.13e-01 9.87e-01f 1\n", + " 101r-1.0314314e+08 3.32e-01 6.34e+00 -3.6 1.21e+04 - 1.00e+00 1.00e+00f 1\n", + " 102r-1.0314312e+08 2.74e-05 1.09e-02 -3.6 3.60e+00 -7.8 1.00e+00 1.00e+00h 1\n", + " 103 -1.0319578e+08 9.61e-05 4.23e+01 -3.8 8.11e+03 - 9.97e-01 1.00e+00F 1\n", + " 104 -1.0413984e+08 4.94e+00 1.28e+03 -3.8 1.56e+06 - 8.31e-01 1.60e-01f 1\n", + " 105 -1.0414099e+08 4.85e+00 1.30e+03 -3.8 4.79e+04 - 1.33e-01 1.69e-02h 1\n", + " 106 -1.0417962e+08 1.56e+01 1.28e+03 -3.8 8.29e+06 - 9.95e-04 1.31e-02f 1\n", + " 107 -1.0415007e+08 1.55e+01 1.39e+01 -3.8 9.94e+04 - 9.52e-01 1.00e+00h 1\n", + " 108 -1.0417530e+08 2.20e+02 1.98e-01 -3.8 6.87e+04 - 9.90e-01 9.64e-01h 1\n", + " 109 -1.0428156e+08 1.32e+04 8.97e+01 -3.8 3.02e+06 - 7.12e-01 1.63e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110 -1.0426214e+08 2.88e+02 4.67e+01 -3.8 2.97e+05 - 5.07e-01 1.00e+00h 1\n", + " 111 -1.0426904e+08 1.71e+03 4.37e+01 -3.8 9.53e+06 - 4.40e-02 1.74e-01H 1\n", + " 112 -1.0427745e+08 1.25e+03 2.84e+00 -3.8 1.36e+06 - 9.80e-01 5.51e-01h 1\n", + " 113 -1.0427831e+08 4.62e+02 1.37e-03 -3.8 6.34e+05 - 1.00e+00 1.00e+00h 1\n", + " 114 -1.0427838e+08 1.66e+00 5.16e-06 -3.8 1.36e+04 - 1.00e+00 1.00e+00h 1\n", + " 115 -1.0427881e+08 2.67e+00 2.14e+02 -5.7 8.92e+04 - 9.86e-01 1.00e+00h 1\n", + " 116 -1.0427883e+08 1.12e-01 1.14e-03 -5.7 1.75e+04 - 1.00e+00 9.65e-01h 1\n", + " 117 -1.0427883e+08 2.06e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", + " 118 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", + " 119 -1.0427884e+08 3.73e-09 2.76e-13 -8.6 7.19e-01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120 -1.0427884e+08 1.86e-09 9.31e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 120\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -1.6119507851267775e+02 -1.0427883997848789e+08\n", + "Dual infeasibility......: 9.3067037146559845e-12 6.0206073060194729e-06\n", + "Constraint violation....: 1.0913936421275139e-10 1.8626451492309570e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 1.4067955341264719e-11 9.1007124869564871e-06\n", + "Overall NLP error.......: 1.0913936421275139e-10 9.1007124869564871e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 255\n", + "Number of objective gradient evaluations = 101\n", + "Number of equality constraint evaluations = 255\n", + "Number of inequality constraint evaluations = 255\n", + "Number of equality constraint Jacobian evaluations = 121\n", + "Number of inequality constraint Jacobian evaluations = 121\n", + "Number of Lagrangian Hessian evaluations = 120\n", + "Total seconds in IPOPT = 0.174\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1236\n", + "Number of nonzeros in inequality constraint Jacobian.: 10\n", + "Number of nonzeros in Lagrangian Hessian.............: 779\n", + "\n", + "Total number of variables............................: 410\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 337\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 405\n", + "Total number of inequality constraints...............: 10\n", + " inequality constraints with only lower bounds: 5\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 5\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -1.0301714e+08 2.98e+05 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -1.0365412e+08 1.32e+05 4.21e+01 -1.0 8.57e+04 - 8.59e-01 5.52e-01h 1\n", + " 2 -1.0410108e+08 5.26e+04 7.56e+03 -1.0 5.09e+04 - 9.61e-01 5.97e-01h 1\n", + " 3 -1.0413437e+08 2.06e+04 2.27e+02 -1.0 2.41e+04 - 9.37e-01 6.07e-01h 1\n", + " 4 -1.0424131e+08 1.93e+02 5.00e+03 -1.0 1.94e+05 - 9.87e-01 9.90e-01h 1\n", + " 5 -1.0420077e+08 9.43e+00 3.43e+03 -1.0 1.40e+05 - 9.11e-01 9.91e-01h 1\n", + " 6 -1.0416592e+08 2.19e+01 9.98e+05 -1.0 7.17e+05 - 7.26e-01 1.56e-02f 7\n", + " 7 -1.0366377e+08 9.17e+01 5.74e+05 -1.0 4.94e+05 - 5.51e-01 1.00e+00H 1\n", + " 8 -1.0363147e+08 9.84e+01 7.49e+06 -1.0 9.50e+05 - 9.90e-01 1.56e-02f 7\n", + " 9 -1.0252180e+08 7.86e+02 3.75e+04 -1.0 1.53e+06 - 7.68e-01 1.00e+00F 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -1.0190033e+08 6.00e+00 1.87e+03 -1.0 2.37e+05 - 1.00e+00 1.00e+00H 1\n", + " 11 -1.0201665e+08 1.13e+01 8.51e+01 -1.0 1.34e+05 - 1.00e+00 1.00e+00H 1\n", + " 12 -1.0416792e+08 1.89e+04 2.50e+06 -2.5 1.28e+06 - 3.10e-01 5.67e-01f 1\n", + " 13 -1.0432990e+08 7.37e+04 1.94e+05 -2.5 1.61e+06 - 8.21e-01 6.69e-01h 1\n", + " 14 -1.0425973e+08 1.27e+02 1.47e+03 -2.5 4.32e+04 - 1.00e+00 1.00e+00h 1\n", + " 15 -1.0426575e+08 1.07e+01 1.87e-01 -2.5 5.16e+04 - 1.00e+00 1.00e+00h 1\n", + " 16 -1.0427763e+08 2.48e+01 2.62e+01 -3.8 6.19e+04 - 1.00e+00 1.00e+00h 1\n", + " 17 -1.0427797e+08 9.99e+01 2.44e-03 -3.8 3.85e+05 - 1.00e+00 1.00e+00h 1\n", + " 18 -1.0427790e+08 1.94e+00 1.79e-05 -3.8 5.18e+04 - 1.00e+00 1.00e+00h 1\n", + " 19 -1.0427873e+08 8.25e+00 5.26e+02 -5.7 1.32e+05 - 9.65e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 -1.0427883e+08 1.02e+00 6.20e-03 -5.7 6.34e+04 - 1.00e+00 9.13e-01h 1\n", + " 21 -1.0427883e+08 2.22e-03 7.11e-08 -5.7 2.00e+03 - 1.00e+00 1.00e+00f 1\n", + " 22 -1.0427884e+08 2.66e-03 1.10e-05 -8.6 3.26e+03 - 1.00e+00 1.00e+00h 1\n", + " 23 -1.0427884e+08 1.16e-08 1.87e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", + " 24 -1.0427884e+08 4.19e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 24\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -7.4466968713582887e+01 -1.0427883997850095e+08\n", + "Dual infeasibility......: 2.0257749632681967e-11 2.8367673194755198e-05\n", + "Constraint violation....: 1.3824319466948509e-10 4.1909515857696533e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 6.5249453183278187e-12 9.1371213367822650e-06\n", + "Overall NLP error.......: 1.3824319466948509e-10 2.8367673194755198e-05\n", + "\n", + "\n", + "Number of objective function evaluations = 52\n", + "Number of objective gradient evaluations = 25\n", + "Number of equality constraint evaluations = 52\n", + "Number of inequality constraint evaluations = 52\n", + "Number of equality constraint Jacobian evaluations = 25\n", + "Number of inequality constraint Jacobian evaluations = 25\n", + "Number of Lagrangian Hessian evaluations = 24\n", + "Total seconds in IPOPT = 0.026\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Optimal solution process results:\n", + "\n", + "\n", + "Extent of reaction: 311.3069854950048\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : -0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.8500000099996615\n", + "Reactor duty (MW): -59.34022107299101\n", + "Duty from Reaction (MW)): 28.216865165267237\n", + "Compressor work (MW): -4.7980486241206324e-24\n", + "Turbine work (MW): -2.491301208383993\n", + "Feed Mixer outlet temperature (C)): 20.051714213753485\n", + "Recycle Mixer outlet temperature (C)): 41.54321437801826\n", + "Feed Compressor outlet temperature (C)): 41.54321437801826\n", + "Feed Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 231.85000478422364\n", + "Turbine outlet temperature (C)): 141.50037862882186\n", + "Turbine outlet pressure (Pa)): 1487177.2483574806\n", + "Cooler outlet temperature (C)): 52.56999699077659\n", + "Flash outlet temperature (C)): 134.0\n", + "Purge percentage (amount of vapor vented to exhaust): 9.999999000026644 %\n", + "Methanol recovery(%): 92.05882105498134\n", + "annualized capital cost ($/year) = 259559.90821288814\n", + "operating cost ($/year) = 525130020.70956033\n", + "sales ($/year) = 140033684437.28268\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 104278839.97850095\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 22.743\n", + " Total Mole Fraction CH4 dimensionless 4.1946e-05\n", + " Total Mole Fraction CO dimensionless 0.24155\n", + " Total Mole Fraction H2 dimensionless 0.64134\n", + " Total Mole Fraction CH3OH dimensionless 0.11706\n", + " Molar Enthalpy joule / mole -47286.\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 308.65\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3792e+05\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", + "m.fs.S101.split_fraction_lb = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", + ") # min 10% purge\n", + "m.fs.S101.split_fraction_ub = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", + ") # max 50% purge\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "\n", + "# Pass 1: smoothed VLE transition\n", + "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "\n", + "\n", + "solver.options[\"max_iter\"] = 200\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "# Pass 2: restore default smoothness\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1236\n", - "Number of nonzeros in inequality constraint Jacobian.: 10\n", - "Number of nonzeros in Lagrangian Hessian.............: 779\n", - "\n", - "Total number of variables............................: 410\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 337\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 405\n", - "Total number of inequality constraints...............: 10\n", - " inequality constraints with only lower bounds: 5\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 5\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -1.0301714e+08 2.98e+05 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -1.0365412e+08 1.32e+05 4.21e+01 -1.0 8.57e+04 - 8.59e-01 5.52e-01h 1\n", - " 2 -1.0410108e+08 5.26e+04 7.56e+03 -1.0 5.09e+04 - 9.61e-01 5.97e-01h 1\n", - " 3 -1.0413437e+08 2.06e+04 2.27e+02 -1.0 2.41e+04 - 9.37e-01 6.07e-01h 1\n", - " 4 -1.0424131e+08 1.93e+02 5.00e+03 -1.0 1.94e+05 - 9.87e-01 9.90e-01h 1\n", - " 5 -1.0420077e+08 9.43e+00 3.43e+03 -1.0 1.40e+05 - 9.11e-01 9.91e-01h 1\n", - " 6 -1.0416592e+08 2.19e+01 9.98e+05 -1.0 7.17e+05 - 7.26e-01 1.56e-02f 7\n", - " 7 -1.0366377e+08 9.17e+01 5.74e+05 -1.0 4.94e+05 - 5.51e-01 1.00e+00H 1\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, recycling methanol and gases from the flash vapor achieves much greater methanol production, and process cost increases are small compared to the increase in revenue. Note that the reaction conversion and flash inlet temperature did not change, and we obtain the same percentage methanol recovery. We can see in the stream tables that far more of the inlet material exits as methanol than in the non-recycle process (note that we do not have a mole balance due to the reaction stoichiometry). The results show a slight increase in equipment and operating costs from increased throughput on each unit." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 8 -1.0363147e+08 9.84e+01 7.49e+06 -1.0 9.50e+05 - 9.90e-01 1.56e-02f 7\n", - " 9 -1.0252180e+08 7.86e+02 3.75e+04 -1.0 1.53e+06 - 7.68e-01 1.00e+00F 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -1.0190033e+08 6.00e+00 1.87e+03 -1.0 2.37e+05 - 1.00e+00 1.00e+00H 1\n", - " 11 -1.0201665e+08 1.13e+01 8.51e+01 -1.0 1.34e+05 - 1.00e+00 1.00e+00H 1\n", - " 12 -1.0416792e+08 1.89e+04 2.50e+06 -2.5 1.28e+06 - 3.10e-01 5.67e-01f 1\n", - " 13 -1.0432990e+08 7.37e+04 1.94e+05 -2.5 1.61e+06 - 8.21e-01 6.69e-01h 1\n", - " 14 -1.0425973e+08 1.27e+02 1.47e+03 -2.5 4.32e+04 - 1.00e+00 1.00e+00h 1\n", - " 15 -1.0426575e+08 1.07e+01 1.87e-01 -2.5 5.16e+04 - 1.00e+00 1.00e+00h 1\n", - " 16 -1.0427763e+08 2.48e+01 2.62e+01 -3.8 6.19e+04 - 1.00e+00 1.00e+00h 1\n", - " 17 -1.0427797e+08 9.99e+01 2.44e-03 -3.8 3.85e+05 - 1.00e+00 1.00e+00h 1\n", - " 18 -1.0427790e+08 1.94e+00 1.79e-05 -3.8 5.18e+04 - 1.00e+00 1.00e+00h 1\n", - " 19 -1.0427873e+08 8.25e+00 5.26e+02 -5.7 1.32e+05 - 9.65e-01 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -1.0427883e+08 1.02e+00 6.20e-03 -5.7 6.34e+04 - 1.00e+00 9.13e-01h 1\n", - " 21 -1.0427883e+08 2.22e-03 7.11e-08 -5.7 2.00e+03 - 1.00e+00 1.00e+00f 1\n", - " 22 -1.0427884e+08 2.66e-03 1.10e-05 -8.6 3.26e+03 - 1.00e+00 1.00e+00h 1\n", - " 23 -1.0427884e+08 1.16e-08 1.82e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", - " 24 -1.0427884e+08 3.14e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 24\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -7.4466968713582915e+01 -1.0427883997850099e+08\n", - "Dual infeasibility......: 2.0257749320973842e-11 2.8367672758258825e-05\n", - "Constraint violation....: 1.3824319466948509e-10 3.1432136893272400e-09\n", - "Complementarity.........: 6.5249453183277711e-12 9.1371213367821990e-06\n", - "Overall NLP error.......: 1.3824319466948509e-10 2.8367672758258825e-05\n", - "\n", - "\n", - "Number of objective function evaluations = 52\n", - "Number of objective gradient evaluations = 25\n", - "Number of equality constraint evaluations = 52\n", - "Number of inequality constraint evaluations = 52\n", - "Number of equality constraint Jacobian evaluations = 25\n", - "Number of inequality constraint Jacobian evaluations = 25\n", - "Number of Lagrangian Hessian evaluations = 24\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.028\n", - "Total CPU secs in NLP function evaluations = 0.001\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 6. Summary\n", + "The present example demonstrates building, initializing and optimizing a methanol synthesis problem in IDAES. The imported scripts implement models from the IDAES pre-defined unit model library, the IDAES Property and Reaction Framework, targeted thermophysical properties for specific unit blocks, Pyomo's Sequential Decomposition methods, the IDAES Costing Framework for capital cost calculations, and integration of custom surrogate expressions for operating cost calculations. The methanol synthesis flowsheet methods may be imported into any external script, and users may build, initialize and optimize the entire model via the `main()` method in each flowsheet." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal solution process results:\n", - "\n", - "\n", - "Extent of reaction: 311.30698549500477\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.8500000099996615\n", - "Reactor duty (MW): -59.340221072991014\n", - "Duty from Reaction (MW)): 28.216865165267233\n", - "Compressor work (MW): 1.2861669211016399e-24\n", - "Turbine work (MW): -2.4913012083840025\n", - "Feed Mixer outlet temperature (C)): 20.05171421375354\n", - "Recycle Mixer outlet temperature (C)): 41.54321437801775\n", - "Feed Compressor outlet temperature (C)): 41.54321437801792\n", - "Feed Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 231.85000478422364\n", - "Turbine outlet temperature (C)): 141.50037862882152\n", - "Turbine outlet pressure (Pa)): 1487177.2483574792\n", - "Cooler outlet temperature (C)): 52.56999699077659\n", - "Flash outlet temperature (C)): 134.0\n", - "Purge percentage (amount of vapor vented to exhaust): 9.999999000026644 %\n", - "Methanol recovery(%): 92.05882105498138\n", - "annualized capital cost ($/year) = 259559.90821288762\n", - "operating cost ($/year) = 525130020.7095608\n", - "sales ($/year) = 140033684437.2827\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 104278839.97850098\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 22.743\n", - " Total Mole Fraction CH4 dimensionless 4.1946e-05\n", - " Total Mole Fraction CO dimensionless 0.24155\n", - " Total Mole Fraction H2 dimensionless 0.64134\n", - " Total Mole Fraction CH3OH dimensionless 0.11706\n", - " Molar Enthalpy joule / mole -47286.\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 308.65\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3792e+05\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n" - ] + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:13.775587500Z", + "start_time": "2026-02-20T21:01:13.771970400Z" + } + }, + "outputs": [], + "source": [] } - ], - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", - "m.fs.S101.split_fraction_lb = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", - ") # min 10% purge\n", - "m.fs.S101.split_fraction_ub = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", - ") # max 50% purge\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "\n", - "# Pass 1: smoothed VLE transition\n", - "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "# Pass 2: restore default smoothness\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, recycling methanol and gases from the flash vapor achieves much greater methanol production, and process cost increases are small compared to the increase in revenue. Note that the reaction conversion and flash inlet temperature did not change, and we obtain the same percentage methanol recovery. We can see in the stream tables that far more of the inlet material exits as methanol than in the non-recycle process (note that we do not have a mole balance due to the reaction stoichiometry). The results show a slight increase in equipment and operating costs from increased throughput on each unit." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 6. Summary\n", - "The present example demonstrates building, initializing and optimizing a methanol synthesis problem in IDAES. The imported scripts implement models from the IDAES pre-defined unit model library, the IDAES Property and Reaction Framework, targeted thermophysical properties for specific unit blocks, Pyomo's Sequential Decomposition methods, the IDAES Costing Framework for capital cost calculations, and integration of custom surrogate expressions for operating cost calculations. The methanol synthesis flowsheet methods may be imported into any external script, and users may build, initialize and optimize the entire model via the `main()` method in each flowsheet." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:18.114029600Z", - "start_time": "2026-02-20T21:01:18.109467400Z" + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.11" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_test.ipynb b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_test.ipynb index 41bb9cb9..d78f7237 100644 --- a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_test.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_test.ipynb @@ -1,4342 +1,2447 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:12.077272400Z", - "start_time": "2026-02-20T21:01:12.065134800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:48.799943Z", - "iopub.status.busy": "2026-02-20T21:02:48.799943Z", - "iopub.status.idle": "2026-02-20T21:02:48.804200Z", - "shell.execute_reply": "2026-02-20T21:02:48.804200Z" - }, - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Methanol Synthesis Flowsheet Example\n", - "Maintainer: Brandon Paul \n", - "Author: Brandon Paul \n", - "Updated: 2023-06-01 \n", - "\n", - "The purpose of this notebook is to demonstrate flowsheet synthesis integrating IDAES modeling tools, including the Unit Model Library, Property and Reaction Framework, IDAES scaling tools and the Process Costing Framework. The example leverages imports from external flowsheet scripts, and demonstrates implementation of separate VLE and vapor-only property packages to reduce model complexity where applicable.\n", - "\n", - "## Simplified Hydrogen Reformation System\n", - "\n", - "This example demonstrates a steady-state model of methanol synthesis from hydrogen and carbon monoxide. To simulate relevant natural gas components, the reactant vapors are mixed stoichiometrically and brought to optimal reaction conditions prior to entering the gas-phase reactor. Vapor liquid equilibrium is mainly applicable in the post-reactor Flash unit for methanol recovery, and is accounted for by separate vapor and VLE thermophysical property packages. See `methanol_flowsheet.py` for more information on how to assemble the flowsheet, as well as [idaes_examples.mod.methanol.methanol_ideal_VLE.py](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_VLE.py), [idaes_examples.mod.methanol.methanol_ideal_vapor](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_vapor.py) and [idaes_examples.mod.methanol.methanol_reactions](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_reactions.py) for more information on the thermophyscial and reaction properties.\n", - "\n", - "This example is a reasonable approximation for gas-phase methanol synthesis systems and does not represent any particular chemical process. To simplify the system and increase tractability, hydrogen and carbon monoxide feeds are considered in lieu of multi-step mechanisms for carbon dioxide conversion to methanol. General process descriptions for gas-phase synthesis, as well as thermophysical and reaction properties for carbon monoxide hydrogenation, were taken from the following publication:\n", - "\n", - "Nieminen, H.; Laari, A.; Koiranen, T. CO2 Hydrogenation to Methanol by a Liquid-Phase Process with Alcoholic Solvents: A Techno-Economic Analysis. Processes 2019, 7, 405. https://doi.org/10.3390/pr7070405" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. Introduction\n", - "\n", - "This example demonstrates a simulation of methanol synthesis from hydrogen and carbon monoxide. Each methanol flowsheet module includes several built-in methods. This notebook demonstrates building the flowsheet, implementing model scaling, initialization and solving a square problem, costing and final constrained optimization.\n", - "\n", - "The ```build_model()``` method creates the Pyomo concrete model and builds the flowsheet by importing thermophysical and reaction properties and unit models and defining stream connections between these units. This method also implements appropriate default scaling on state and property variables.\n", - "\n", - "The ```set_inputs()``` method adds the appropriate initial specifications on the feed streams and unit operations. Specifications upstream of the reactor largely remain fixed throughout the optimization.\n", - "\n", - "The ```scale_flowsheet()``` method implements generic variable, unit model state variable, unit model constraint and Arc equality constraint scaling via IDAES scaling tools. Scaling factors are hard-coded in the flowsheet scripts to adjust for order of magnitude factors in appropriate constraints and simplify numerical solver calculations.\n", - "\n", - "The ```initialize_flowsheet()``` method uses the initial guess to initialize the models sequentially, solving each unit and propagating the results to the outlet stream to converge the next unit more quickly. This occurs just before the flowsheet-level solver call.\n", - "\n", - "The ```add_costing()``` method creates new variables and constraints related to unit model capital cost and operating cost calculations, and defines an objective function for the process economics. This method is called after the flowsheet-level solver call, and the flowsheet is resolved once costing is added. Capital costs are estimated using built-in costing methods within IDAES, and operating costs are estimated from a combination of known cost coefficients and surrogate models.\n", - "\n", - "The ```report()``` method displays relevant model results after the flowsheet has been fully solved." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2. Problem Statement \n", - "\n", - "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", - "\n", - "## 2.1. Main Inputs: \n", - "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", - "- Pre-reactor compressor outlet pressure (Pa)\n", - "- Pre-reactor heater outlet temperature (K)\n", - "\n", - "## 2.2. Main Outputs:\n", - "- Extent of reaction (mol/s)\n", - "- Reactor duty (W)\n", - "- Turbine duty (W)\n", - "- Methanol recovery (%)\n", - "- Annual revenue (USD/year)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:12.101680200Z", - "start_time": "2026-02-20T21:01:12.087272100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:48.805381Z", - "iopub.status.busy": "2026-02-20T21:02:48.805381Z", - "iopub.status.idle": "2026-02-20T21:02:48.811980Z", - "shell.execute_reply": "2026-02-20T21:02:48.811980Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3. Import and Solve Flowsheet\n", - "## 3.1 Import Pyomo and IDAES Libraries" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, let's import the relevant Pyomo and IDAES Libraries:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:12.133188600Z", - "start_time": "2026-02-20T21:01:12.108593100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:48.843518Z", - "iopub.status.busy": "2026-02-20T21:02:48.843518Z", - "iopub.status.idle": "2026-02-20T21:02:51.487294Z", - "shell.execute_reply": "2026-02-20T21:02:51.487294Z" - } - }, - "outputs": [], - "source": [ - "import pytest\n", - "import os\n", - "\n", - "# Import Pyomo libraries\n", - "from pyomo.environ import (\n", - " Constraint,\n", - " Objective,\n", - " Var,\n", - " Expression,\n", - " Param,\n", - " ConcreteModel,\n", - " TransformationFactory,\n", - " value,\n", - " maximize,\n", - " units as pyunits,\n", - ")\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.network import Arc\n", - "\n", - "# Import IDAES core libraries\n", - "from idaes.core import FlowsheetBlock\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util import scaling as iscale\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "from idaes.core.util.initialization import propagate_state\n", - "\n", - "# Import required property modules\n", - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "\n", - "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", - "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", - "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", - "\n", - "from idaes.models.unit_models import (\n", - " Feed,\n", - " Mixer,\n", - " Heater,\n", - " Compressor,\n", - " Turbine,\n", - " StoichiometricReactor,\n", - " Flash,\n", - " Product,\n", - ")\n", - "from idaes.models.unit_models.mixer import MomentumMixingType\n", - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core import UnitModelCostingBlock\n", - "from idaes.models.costing.SSLW import SSLWCosting\n", - "\n", - "# import flowsheet functions\n", - "from methanol_flowsheet import (\n", - " build_model,\n", - " set_inputs,\n", - " scale_flowsheet,\n", - " initialize_flowsheet,\n", - " add_costing,\n", - " report,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.2 Build and Solve Flowsheet\n", - "The methanol flowsheet methods are called sequentially below, following the workflow contained in the ```main()``` method in `methanol_flowsheet.py`. First, let's set the solver options. IDAES contains a default solver `get_solver` which calls IPOPT using standard settings, and we set an iteration cap of 100 to catch nonconverging solver runs." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:12.163219200Z", - "start_time": "2026-02-20T21:01:12.134801600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:51.489319Z", - "iopub.status.busy": "2026-02-20T21:02:51.489319Z", - "iopub.status.idle": "2026-02-20T21:02:51.492852Z", - "shell.execute_reply": "2026-02-20T21:02:51.492852Z" - } - }, - "outputs": [], - "source": [ - "# Set solver options\n", - "solver = get_solver() # IPOPT\n", - "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", - "solver.options = optarg" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will build and solve the initial flowsheet using imported flowsheet methods - see `methanol_flowsheet.py` for complete method scripts.\n", - "\n", - "In the code below, we first define a Pyomo model object and build the model by defining each unit block with relevant property packages. As mentioned earlier, only the Flash unit (and the liquid outlet Product block) employ the VLE property package to ensure fast convergence of vapor-only processes.\n", - "\n", - "The process inputs are set for stoichiometric hydrogen and carbon monoxide feeds according to the process diagram in section 2.2. In the output below, the script returns the expected degrees of freedom for the model for each unit (compressor pressure change, heater duty, reactor duty and conversion, turbine pressure change and efficiency, cooler duty and flash duty and pressure change) and the actual model degrees of freedom before input specification, after the feed inputs are specified (flow, enthalpy, pressure, and composition for each feed) and after the unit model inputs are specified.\n", - "\n", - "After setting process inputs, we have a square problem for initialization. Here, we first implement IDAES scaling tools to create a more tractable problem during the solve step, and then sequentially initialize and propagate results from each unit block. As expected, the model only performs dew and bubble point calculations for the Flash and CH3OH product blocks where liquid phases are present and we obtain a square, solved problem:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:14.890006Z", - "start_time": "2026-02-20T21:01:12.164401100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:51.495253Z", - "iopub.status.busy": "2026-02-20T21:02:51.493863Z", - "iopub.status.idle": "2026-02-20T21:02:53.135410Z", - "shell.execute_reply": "2026-02-20T21:02:53.135410Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unit degrees of freedom\n", - "M101 0\n", - "C101 1\n", - "H101 1\n", - "R101 2\n", - "T101 2\n", - "H102 1\n", - "F101 2\n", - "Total DOF: 23\n", - "DOF after streams specified: 9\n", - "DOF after units specified: 0\n", - "\n", - "2026-02-20 14:02:51 [INFO] idaes.init.fs.H2.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.H2: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.CO.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.CO: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:51 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:52 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:53 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:53 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:53 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:53 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF before solve: 0\n", - "\n", - "Solving initial problem...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 955\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 607\n", - "\n", - "Total number of variables............................: 310\n", - " variables with only lower bounds: 35\n", - " variables with lower and upper bounds: 258\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 310\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 2.79e+02 2.77e+00 -1.0 1.00e-02 - 9.90e-01 9.90e-01h 1\n", - " 2 0.0000000e+00 2.77e+00 1.21e+00 -1.0 1.00e-04 - 9.90e-01 9.90e-01h 1\n", - " 3 0.0000000e+00 6.98e-10 1.00e+03 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 3\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Constraint violation....: 1.1368683772161603e-13 6.9849193096160889e-10\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 1.1368683772161603e-13 6.9849193096160889e-10\n", - "\n", - "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.003\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - } - ], - "source": [ - "# Build and solve flowsheet\n", - "m = ConcreteModel()\n", - "build_model(m) # build flowsheet by adding unit models and property packages\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "\n", - "results = solver.solve(m, tee=True) # initial square problem solve" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:14.896961Z", - "start_time": "2026-02-20T21:01:14.890006Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.136921Z", - "iopub.status.busy": "2026-02-20T21:02:53.136921Z", - "iopub.status.idle": "2026-02-20T21:02:53.140029Z", - "shell.execute_reply": "2026-02-20T21:02:53.140029Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# check optimal termination\n", - "assert results.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.3 Flowsheet Costing and Optimization\n", - "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs. Additional, we calculate reactor operating costs as a function of conversion and assume constant rates for electricity, heating and cooling costs. Capital costs are annualized over 15 years, and revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, including a check on the reaction stoichiometry, relevant duty and state variable values, economic results, and stream tables for feed and product streams:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:15.080743Z", - "start_time": "2026-02-20T21:01:14.897531200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.142545Z", - "iopub.status.busy": "2026-02-20T21:02:53.141539Z", - "iopub.status.idle": "2026-02-20T21:02:53.260308Z", - "shell.execute_reply": "2026-02-20T21:02:53.260308Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving with costing...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 971\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 611\n", - "\n", - "Total number of variables............................: 319\n", - " variables with only lower bounds: 43\n", - " variables with lower and upper bounds: 258\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 319\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8492051e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.9068962e+07 5.76e+04 6.45e+01 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", - " 2 -2.9074767e+07 5.71e+02 9.98e+00 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", - " 3 -2.9074825e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9074825e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 4\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -4.4948186430824137e+01 -2.9074824816033222e+07\n", - "Dual infeasibility......: 3.6708958239217049e-07 2.3745263485255724e-01\n", - "Constraint violation....: 4.5474735088646412e-12 1.0477378964424133e-09\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 2.3745263485255724e-01\n", - "\n", - "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.003\n", - "Total CPU secs in NLP function evaluations = 0.001\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initial solution process results:\n", - "\n", - "\n", - "Extent of reaction: 237.6004779\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.21917830318435\n", - "Duty from Reaction (MW)): 21.536107316856\n", - "Turbine work (MW): -0.9593346445867499\n", - "Mixer outlet temperature (C)): 20.051714213753257\n", - "Compressor outlet temperature (C)): 20.051714213753257\n", - "Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.8781524424324\n", - "Turbine outlet pressure (Pa)): 3100000.0\n", - "Cooler outlet temperature (C)): 134.0\n", - "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 60.004430129216836\n", - "annualized capital cost ($/year) = 219790.5044704343\n", - "operating cost ($/year) = 380701687.4964806\n", - "sales ($/year) = 64685201172.198135\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29074824.816033214\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 336.23\n", - " Total Mole Fraction CH4 dimensionless 2.8373e-06\n", - " Total Mole Fraction CO dimensionless 0.23555\n", - " Total Mole Fraction H2 dimensionless 0.48181\n", - " Total Mole Fraction CH3OH dimensionless 0.28263\n", - " Molar Enthalpy joule / mole -80218.\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 142.57\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3813e+05\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "print(\"Solving with costing...\")\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:15.090200200Z", - "start_time": "2026-02-20T21:01:15.081745600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.261813Z", - "iopub.status.busy": "2026-02-20T21:02:53.261813Z", - "iopub.status.idle": "2026-02-20T21:02:53.266090Z", - "shell.execute_reply": "2026-02-20T21:02:53.266090Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# check optimal termination\n", - "assert results2.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:15.228147700Z", - "start_time": "2026-02-20T21:01:15.091200900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.268165Z", - "iopub.status.busy": "2026-02-20T21:02:53.268165Z", - "iopub.status.idle": "2026-02-20T21:02:53.374557Z", - "shell.execute_reply": "2026-02-20T21:02:53.374557Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Solving optimization problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 975\n", - "Number of nonzeros in inequality constraint Jacobian.: 8\n", - "Number of nonzeros in Lagrangian Hessian.............: 613\n", - "\n", - "Total number of variables............................: 322\n", - " variables with only lower bounds: 43\n", - " variables with lower and upper bounds: 259\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 318\n", - "Total number of inequality constraints...............: 8\n", - " inequality constraints with only lower bounds: 4\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 4\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8492012e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.8402807e+07 2.72e+04 9.71e+01 -1.0 8.82e+06 - 4.99e-02 2.59e-02h 1\n", - " 2 -2.8406592e+07 2.70e+04 9.55e+01 -1.0 8.56e+06 - 7.51e-02 8.58e-03h 1\n", - " 3 -2.8493711e+07 2.29e+04 3.69e+02 -1.0 8.41e+06 - 1.67e-01 1.52e-01h 1\n", - " 4 -2.8493256e+07 2.28e+04 1.20e+04 -1.0 4.60e+06 - 1.00e-01 2.61e-03h 1\n", - " 5 -2.8504483e+07 2.24e+04 1.20e+04 -1.0 4.52e+06 - 2.44e-02 2.38e-02h 1\n", - " 6 -2.8536508e+07 2.16e+04 2.28e+04 -1.0 4.39e+06 - 5.48e-02 6.86e-02h 1\n", - " 7 -2.8537589e+07 2.16e+04 1.35e+05 -1.0 3.94e+06 - 2.56e-01 2.49e-03h 1\n", - " 8 -2.8537637e+07 2.15e+04 6.77e+06 -1.0 1.30e+06 - 4.68e-01 1.17e-04h 1\n", - " 9 -2.8910081e+07 8.51e+04 2.07e+06 -1.0 1.31e+06 - 4.38e-01 9.05e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -2.8916017e+07 7.81e+04 1.11e+08 -1.0 9.39e+04 -4.0 3.56e-03 8.26e-02h 1\n", - " 11 -2.8916050e+07 7.80e+04 1.11e+08 -1.0 8.73e+04 -4.5 9.12e-02 9.05e-04h 1\n", - " 12 -2.8951501e+07 1.29e+04 3.00e+07 -1.0 8.73e+04 - 1.37e-02 9.90e-01h 1\n", - " 13 -2.8964697e+07 3.52e+03 9.82e+06 -1.0 2.95e+04 - 8.80e-01 9.92e-01h 1\n", - " 14 -2.9150638e+07 4.25e+00 6.53e+07 -1.0 1.59e+04 - 9.88e-01 1.00e+00h 1\n", - " 15 -3.2694771e+07 3.47e+03 1.38e+08 -1.0 3.00e+05 - 3.58e-01 1.00e+00f 1\n", - " 16 -3.9657884e+07 3.74e+02 4.98e+06 -1.0 6.48e+05 - 9.11e-01 1.00e+00F 1\n", - " 17 -5.8700677e+07 2.03e+04 1.12e+06 -1.0 2.00e+06 - 2.65e-01 1.00e+00F 1\n", - " 18 -7.8085174e+07 1.40e+05 4.14e+05 -1.0 4.34e+06 - 7.55e-01 7.57e-01f 1\n", - " 19 -7.9333792e+07 1.60e+05 2.63e+05 -1.0 3.52e+06 - 9.63e-01 3.03e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -7.7164009e+07 3.20e+03 7.59e+03 -1.0 4.56e+05 - 9.91e-01 1.00e+00h 1\n", - " 21 -7.7545831e+07 3.83e+03 5.53e+01 -1.0 2.78e+05 - 1.00e+00 1.00e+00h 1\n", - " 22 -7.7683360e+07 9.76e+02 2.23e+06 -2.5 6.32e+04 - 1.00e+00 7.70e-01h 1\n", - " 23 -7.7696221e+07 8.35e+00 1.48e+02 -2.5 6.87e+04 - 1.00e+00 1.00e+00h 1\n", - " 24 -7.7696183e+07 8.31e-03 4.61e-03 -2.5 2.13e+03 - 1.00e+00 1.00e+00h 1\n", - " 25 -7.7699949e+07 5.36e+00 1.27e+04 -5.7 7.60e+04 - 9.49e-01 9.94e-01f 1\n", - " 26 -7.7700458e+07 8.84e+01 1.03e+03 -5.7 3.66e+05 - 9.25e-01 9.72e-01h 1\n", - " 27 -7.7700530e+07 1.74e+01 1.01e+01 -5.7 6.59e+04 - 1.00e+00 8.03e-01h 1\n", - " 28 -7.7700531e+07 2.07e-04 4.22e-06 -5.7 1.25e+03 - 1.00e+00 1.00e+00h 1\n", - " 29 -7.7700536e+07 9.48e-04 1.29e-01 -8.6 1.69e+03 - 1.00e+00 9.99e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.7700536e+07 6.52e-09 5.32e-11 -8.6 1.52e+00 - 1.00e+00 1.00e+00f 1\n", - " 31 -7.7700536e+07 8.38e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 31\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -1.2012103932708916e+02 -7.7700535938862860e+07\n", - "Dual infeasibility......: 6.9713197782916848e-11 4.5094122229452131e-05\n", - "Constraint violation....: 9.4587448984384537e-11 8.3819031715393066e-09\n", - "Complementarity.........: 1.4074777632989367e-11 9.1042982264387185e-06\n", - "Overall NLP error.......: 9.4587448984384537e-11 4.5094122229452131e-05\n", - "\n", - "\n", - "Number of objective function evaluations = 34\n", - "Number of objective gradient evaluations = 32\n", - "Number of equality constraint evaluations = 34\n", - "Number of inequality constraint evaluations = 34\n", - "Number of equality constraint Jacobian evaluations = 32\n", - "Number of inequality constraint Jacobian evaluations = 32\n", - "Number of Lagrangian Hessian evaluations = 31\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.023\n", - "Total CPU secs in NLP function evaluations = 0.004\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal solution process results:" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\n", - "Extent of reaction: 269.2805447879921\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.8500000099999546\n", - "Reactor duty (MW): -51.363573577545786\n", - "Duty from Reaction (MW)): 24.407588579583603\n", - "Turbine work (MW): -1.9904899177794815\n", - "Mixer outlet temperature (C)): 20.0517142137536\n", - "Compressor outlet temperature (C)): 20.0517142137536\n", - "Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 231.85000468716584\n", - "Turbine outlet temperature (C)): 139.85888172675686\n", - "Turbine outlet pressure (Pa)): 1427653.3547820917\n", - "Cooler outlet temperature (C)): 52.56999709299214\n", - "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 92.8035547465754\n", - "annualized capital cost ($/year) = 235547.18924473316\n", - "operating cost ($/year) = 451663512.6847629\n", - "sales ($/year) = 113381889876.90082\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 77700535.93886285\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 165.54\n", - " Total Mole Fraction CH4 dimensionless 5.7630e-06\n", - " Total Mole Fraction CO dimensionless 0.28706\n", - " Total Mole Fraction H2 dimensionless 0.59587\n", - " Total Mole Fraction CH3OH dimensionless 0.11706\n", - " Molar Enthalpy joule / mole -52313.\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 249.90\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3792e+05\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "opt_res = solver.solve(m, tee=True)\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, the process achieves a much greater revenue as a result of increasing conversion and lowering the inlet temperature to the Flash unit to encourage methanol recovery in the liquid phase. The results show a slight increase in equipment and operating costs from these changes, as well as a small loss of methanol in the exhaust." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:15.238140100Z", - "start_time": "2026-02-20T21:01:15.228701500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.376067Z", - "iopub.status.busy": "2026-02-20T21:02:53.376067Z", - "iopub.status.idle": "2026-02-20T21:02:53.381088Z", - "shell.execute_reply": "2026-02-20T21:02:53.381088Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# testing model results\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "assert value(m.fs.R101.rate_reaction_extent[0, \"R1\"]) == pytest.approx(\n", - " 269.2805, rel=1e-5\n", - ")\n", - "assert value(m.fs.R101.heat_duty[0]) / 1e6 == pytest.approx(-51.3636, rel=1e-5)\n", - "assert value(m.fs.T101.work_isentropic[0]) / 1e6 == pytest.approx(-1.9905, rel=1e-5)\n", - "assert value(m.fs.F101.recovery * 100) == pytest.approx(92.8036, rel=1e-5)\n", - "assert value(m.fs.objective) / 1e6 == pytest.approx(77.7005, rel=1e-5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 4. Problem Statement - Analyzing Benefit of Recycling Flash Vapor\n", - "\n", - "To increase the efficiency of the process as well as overall methanol production and revenue, we can add a recycle stream to send most of the Flash vapor back to the start of the process. This will reduce methanol loss in the exhaust and increase feed utilization, resulting in increased operating costs and increased production (revenue) at the same conversion. Note that for conversions less than 100%, a simulation with no purge will never converge due to accumulation of gases within the system. Therefore, to ensure we close the mass balance we set a lower bound at 10% purge from the Flash vapor to the exhaust. We expect to see a marginal increase in operating costs due to increased flow, and a much larger increase in overall production resulting in a higher total revenue.\n", - "\n", - "By adding a recycle to the flowsheet, we significantly decrease the tractability of the problem and require a better initial guess. The SequentialDecomposition algorithm automatically determines a stream to *tear*, or use to break the solve loop, and iterates from a set of user-supplied initial guesses until converging on the optimal solution. The code below calls an initialization method to automatically determine the tear stream. See the initialization method of `methanol_flowsheet_w_recycle.py` for further details Sequential Decomposition scheme.\n", - "\n", - "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", - "\n", - "## 4.1. Main Inputs: \n", - "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", - "- Pre-reactor compressor outlet pressure (Pa)\n", - "- Pre-reactor heater outlet temperature (K)\n", - "\n", - "## 4.2. Main Outputs:\n", - "- Extent of reaction (mol/s)\n", - "- Reactor duty (W)\n", - "- Compressor duty (W)\n", - "- Turbine duty (W)\n", - "- Methanol recovery (%)\n", - "- Purge percentage (%)\n", - "- Annual revenue (USD/year)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:15.248401100Z", - "start_time": "2026-02-20T21:01:15.239141700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.383119Z", - "iopub.status.busy": "2026-02-20T21:02:53.383119Z", - "iopub.status.idle": "2026-02-20T21:02:53.387635Z", - "shell.execute_reply": "2026-02-20T21:02:53.387635Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet_recycle.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 5. Import and Solve Recycle Flowsheet\n", - "## 5.1 Import Pyomo and IDAES Libraries\n", - "As we are rebuilding the model, we need to import require Pyomo and IDAES libraries:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:15.257940Z", - "start_time": "2026-02-20T21:01:15.249681700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.389672Z", - "iopub.status.busy": "2026-02-20T21:02:53.389672Z", - "iopub.status.idle": "2026-02-20T21:02:53.395462Z", - "shell.execute_reply": "2026-02-20T21:02:53.395462Z" - } - }, - "outputs": [], - "source": [ - "import pytest\n", - "import os\n", - "\n", - "# Import Pyomo libraries\n", - "from pyomo.environ import (\n", - " Constraint,\n", - " Objective,\n", - " Var,\n", - " Expression,\n", - " Param,\n", - " ConcreteModel,\n", - " TransformationFactory,\n", - " value,\n", - " maximize,\n", - " units as pyunits,\n", - ")\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.network import Arc, SequentialDecomposition\n", - "\n", - "# Import IDAES core libraries\n", - "from idaes.core import FlowsheetBlock\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util import scaling as iscale\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "from idaes.core.util.initialization import propagate_state\n", - "\n", - "# Import required models\n", - "\n", - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "\n", - "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", - "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", - "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", - "\n", - "from idaes.models.unit_models import (\n", - " Feed,\n", - " Mixer,\n", - " Heater,\n", - " Compressor,\n", - " Turbine,\n", - " StoichiometricReactor,\n", - " Flash,\n", - " Separator as Splitter,\n", - " Product,\n", - ")\n", - "from idaes.models.unit_models.mixer import MomentumMixingType\n", - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core import UnitModelCostingBlock\n", - "from idaes.models.costing.SSLW import SSLWCosting\n", - "import idaes.logger as idaeslog\n", - "\n", - "# import flowsheet functions\n", - "from methanol_flowsheet_w_recycle import (\n", - " build_model,\n", - " set_inputs,\n", - " scale_flowsheet,\n", - " initialize_flowsheet,\n", - " add_costing,\n", - " report,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.2 Build and Solve Recycle Flowsheet\n", - "As before, we will first build the flowsheet, set required inputs, initialize and solve a square problem. Recycling methanol to pre-reactor blocks complicates VLE calculations, and limiting VLE calculations to the Flash unit and liquid Product block greatly increases tractability during initialization. All initial feed and unit specifications are identical to the non-recycle case; the Sequential Decomposition algorithm automatically selects the compressor feed as the tear stream and uses \"no recycle\" results as a first guess. In the output below, the solver solves all units and then resolves select blocks with updated inlet results, followed by a full flowsheet solve:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:18.400079700Z", - "start_time": "2026-02-20T21:01:15.257940Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:53.397491Z", - "iopub.status.busy": "2026-02-20T21:02:53.397491Z", - "iopub.status.idle": "2026-02-20T21:02:56.082394Z", - "shell.execute_reply": "2026-02-20T21:02:56.082394Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unit degrees of freedom\n", - "M101 0\n", - "C101 1\n", - "H101 1\n", - "R101 2\n", - "T101 2\n", - "H102 1\n", - "F101 2\n", - "M102 0\n", - "S101 1\n", - "Total DOF: 24\n", - "DOF after streams specified: 10\n", - "DOF after units specified: 0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Tear Stream:\n", - "fs.s02 : fs.M102.outlet to fs.C101.inlet\n", - "\n", - "Calculation order:\n", - "fs.H2\n", - "fs.M101\n", - "fs.R101\n", - "fs.T101\n", - "fs.H102\n", - "fs.F101\n", - "fs.S101\n", - "fs.EXHAUST\n", - "\n", - "Initial DOF = 0\n", - "Solving fs.H2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.CO\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.C101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.M101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "Solving fs.H101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.R101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.T101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.H102\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.F101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.S101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.CH3OH\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.EXHAUST\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.M102\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.H2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.CO\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.M101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:04.629603300Z", + "start_time": "2026-02-20T21:01:04.619279Z" + }, + "tags": [ + "header", + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Methanol Synthesis Flowsheet Example\n", + "Maintainer: Brandon Paul \n", + "Author: Brandon Paul \n", + "Updated: 2023-06-01 \n", + "\n", + "The purpose of this notebook is to demonstrate flowsheet synthesis integrating IDAES modeling tools, including the Unit Model Library, Property and Reaction Framework, IDAES scaling tools and the Process Costing Framework. The example leverages imports from external flowsheet scripts, and demonstrates implementation of separate VLE and vapor-only property packages to reduce model complexity where applicable.\n", + "\n", + "## Simplified Hydrogen Reformation System\n", + "\n", + "This example demonstrates a steady-state model of methanol synthesis from hydrogen and carbon monoxide. To simulate relevant natural gas components, the reactant vapors are mixed stoichiometrically and brought to optimal reaction conditions prior to entering the gas-phase reactor. Vapor liquid equilibrium is mainly applicable in the post-reactor Flash unit for methanol recovery, and is accounted for by separate vapor and VLE thermophysical property packages. See `methanol_flowsheet.py` for more information on how to assemble the flowsheet, as well as [idaes_examples.mod.methanol.methanol_ideal_VLE.py](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_VLE.py), [idaes_examples.mod.methanol.methanol_ideal_vapor](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_vapor.py) and [idaes_examples.mod.methanol.methanol_reactions](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_reactions.py) for more information on the thermophyscial and reaction properties.\n", + "\n", + "This example is a reasonable approximation for gas-phase methanol synthesis systems and does not represent any particular chemical process. To simplify the system and increase tractability, hydrogen and carbon monoxide feeds are considered in lieu of multi-step mechanisms for carbon dioxide conversion to methanol. General process descriptions for gas-phase synthesis, as well as thermophysical and reaction properties for carbon monoxide hydrogenation, were taken from the following publication:\n", + "\n", + "Nieminen, H.; Laari, A.; Koiranen, T. CO2 Hydrogenation to Methanol by a Liquid-Phase Process with Alcoholic Solvents: A Techno-Economic Analysis. Processes 2019, 7, 405. https://doi.org/10.3390/pr7070405" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Introduction\n", + "\n", + "This example demonstrates a simulation of methanol synthesis from hydrogen and carbon monoxide. Each methanol flowsheet module includes several built-in methods. This notebook demonstrates building the flowsheet, implementing model scaling, initialization and solving a square problem, costing and final constrained optimization.\n", + "\n", + "The ```build_model()``` method creates the Pyomo concrete model and builds the flowsheet by importing thermophysical and reaction properties and unit models and defining stream connections between these units. This method also implements appropriate default scaling on state and property variables.\n", + "\n", + "The ```set_inputs()``` method adds the appropriate initial specifications on the feed streams and unit operations. Specifications upstream of the reactor largely remain fixed throughout the optimization.\n", + "\n", + "The ```scale_flowsheet()``` method implements generic variable, unit model state variable, unit model constraint and Arc equality constraint scaling via IDAES scaling tools. Scaling factors are hard-coded in the flowsheet scripts to adjust for order of magnitude factors in appropriate constraints and simplify numerical solver calculations.\n", + "\n", + "The ```initialize_flowsheet()``` method uses the initial guess to initialize the models sequentially, solving each unit and propagating the results to the outlet stream to converge the next unit more quickly. This occurs just before the flowsheet-level solver call.\n", + "\n", + "The ```add_costing()``` method creates new variables and constraints related to unit model capital cost and operating cost calculations, and defines an objective function for the process economics. This method is called after the flowsheet-level solver call, and the flowsheet is resolved once costing is added. Capital costs are estimated using built-in costing methods within IDAES, and operating costs are estimated from a combination of known cost coefficients and surrogate models.\n", + "\n", + "The ```report()``` method displays relevant model results after the flowsheet has been fully solved." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2. Problem Statement \n", + "\n", + "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", + "\n", + "## 2.1. Main Inputs: \n", + "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", + "- Pre-reactor compressor outlet pressure (Pa)\n", + "- Pre-reactor heater outlet temperature (K)\n", + "\n", + "## 2.2. Main Outputs:\n", + "- Extent of reaction (mol/s)\n", + "- Reactor duty (W)\n", + "- Turbine duty (W)\n", + "- Methanol recovery (%)\n", + "- Annual revenue (USD/year)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.EXHAUST\n" - ] + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:04.649464300Z", + "start_time": "2026-02-20T21:01:04.632133500Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet.png\")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 3. Import and Solve Flowsheet\n", + "## 3.1 Import Pyomo and IDAES Libraries" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's import the relevant Pyomo and IDAES Libraries:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:07.389407500Z", + "start_time": "2026-02-20T21:01:04.652988700Z" + } + }, + "outputs": [], + "source": [ + "import pytest\n", + "import os\n", + "\n", + "# Import Pyomo libraries\n", + "from pyomo.environ import (\n", + " Constraint,\n", + " Objective,\n", + " Var,\n", + " Expression,\n", + " Param,\n", + " ConcreteModel,\n", + " TransformationFactory,\n", + " value,\n", + " maximize,\n", + " units as pyunits,\n", + ")\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.network import Arc\n", + "\n", + "# Import IDAES core libraries\n", + "from idaes.core import FlowsheetBlock\n", + "from idaes.core.solvers import get_solver\n", + "from idaes.core.util import scaling as iscale\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "from idaes.core.util.initialization import propagate_state\n", + "\n", + "# Import required property modules\n", + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "\n", + "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", + "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", + "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", + "\n", + "from idaes.models.unit_models import (\n", + " Feed,\n", + " Mixer,\n", + " Heater,\n", + " Compressor,\n", + " Turbine,\n", + " StoichiometricReactor,\n", + " Flash,\n", + " Product,\n", + ")\n", + "from idaes.models.unit_models.mixer import MomentumMixingType\n", + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core import UnitModelCostingBlock\n", + "from idaes.models.costing.SSLW import SSLWCosting\n", + "\n", + "# import flowsheet functions\n", + "from methanol_flowsheet import (\n", + " build_model,\n", + " set_inputs,\n", + " scale_flowsheet,\n", + " initialize_flowsheet,\n", + " add_costing,\n", + " report,\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " " - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3.2 Build and Solve Flowsheet\n", + "The methanol flowsheet methods are called sequentially below, following the workflow contained in the ```main()``` method in `methanol_flowsheet.py`. First, let's set the solver options. IDAES contains a default solver `get_solver` which calls IPOPT using standard settings, and we set an iteration cap of 100 to catch nonconverging solver runs." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "Solving fs.CH3OH\n" - ] + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:07.399593900Z", + "start_time": "2026-02-20T21:01:07.390910200Z" + } + }, + "outputs": [], + "source": [ + "# Set solver options\n", + "solver = get_solver() # IPOPT\n", + "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", + "solver.options = optarg" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will build and solve the initial flowsheet using imported flowsheet methods - see `methanol_flowsheet.py` for complete method scripts.\n", + "\n", + "In the code below, we first define a Pyomo model object and build the model by defining each unit block with relevant property packages. As mentioned earlier, only the Flash unit (and the liquid outlet Product block) employ the VLE property package to ensure fast convergence of vapor-only processes.\n", + "\n", + "The process inputs are set for stoichiometric hydrogen and carbon monoxide feeds according to the process diagram in section 2.2. In the output below, the script returns the expected degrees of freedom for the model for each unit (compressor pressure change, heater duty, reactor duty and conversion, turbine pressure change and efficiency, cooler duty and flash duty and pressure change) and the actual model degrees of freedom before input specification, after the feed inputs are specified (flow, enthalpy, pressure, and composition for each feed) and after the unit model inputs are specified.\n", + "\n", + "After setting process inputs, we have a square problem for initialization. Here, we first implement IDAES scaling tools to create a more tractable problem during the solve step, and then sequentially initialize and propagate results from each unit block. As expected, the model only performs dew and bubble point calculations for the Flash and CH3OH product blocks where liquid phases are present and we obtain a square, solved problem:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.234663Z", + "start_time": "2026-02-20T21:01:07.401096600Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unit degrees of freedom\n", + "M101 0\n", + "C101 1\n", + "H101 1\n", + "R101 2\n", + "T101 2\n", + "H102 1\n", + "F101 2\n", + "Total DOF: 23\n", + "DOF after streams specified: 9\n", + "DOF after units specified: 0\n", + "\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n", + "DOF before solve: 0\n", + "\n", + "Solving initial problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 955\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 607\n", + "\n", + "Total number of variables............................: 310\n", + " variables with only lower bounds: 35\n", + " variables with lower and upper bounds: 258\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 310\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 2.79e+02 2.77e+00 -1.0 1.00e-02 - 9.90e-01 9.90e-01h 1\n", + " 2 0.0000000e+00 2.77e+00 1.21e+00 -1.0 1.00e-04 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 9.31e-10 0.00e+00 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 1.1368683772161603e-13 9.3132257461547852e-10\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 1.1368683772161603e-13 9.3132257461547852e-10\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total seconds in IPOPT = 0.003\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Build and solve flowsheet\n", + "m = ConcreteModel()\n", + "build_model(m) # build flowsheet by adding unit models and property packages\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "\n", + "results = solver.solve(m, tee=True) # initial square problem solve" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.241076500Z", + "start_time": "2026-02-20T21:01:09.235965Z" + }, + "tags": [ + "testing" + ] + }, + "outputs": [], + "source": [ + "# check optimal termination\n", + "assert results.solver.termination_condition == TerminationCondition.optimal" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3.3 Flowsheet Costing and Optimization\n", + "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs. Additional, we calculate reactor operating costs as a function of conversion and assume constant rates for electricity, heating and cooling costs. Capital costs are annualized over 15 years, and revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, including a check on the reaction stoichiometry, relevant duty and state variable values, economic results, and stream tables for feed and product streams:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.373826200Z", + "start_time": "2026-02-20T21:01:09.242152800Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving with costing...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 971\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 611\n", + "\n", + "Total number of variables............................: 319\n", + " variables with only lower bounds: 43\n", + " variables with lower and upper bounds: 258\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 319\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8492051e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.9068962e+07 5.76e+04 6.45e+01 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", + " 2 -2.9074767e+07 5.71e+02 9.98e+00 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", + " 3 -2.9074825e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9074825e+07 1.63e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9074825e+07 1.16e-09 9.87e-08 -1.0 2.66e-08 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 5\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -4.4948186430824109e+01 -2.9074824816033181e+07\n", + "Dual infeasibility......: 9.8709848486689587e-08 6.3850664070387003e-02\n", + "Constraint violation....: 4.5474735088646412e-12 1.1641532182693481e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.8709848486689587e-08 6.3850664070387003e-02\n", + "\n", + "\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 6\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Initial solution process results:\n", + "\n", + "\n", + "Extent of reaction: 237.60047790000004\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.75\n", + "Reactor duty (MW): -45.21917830318437\n", + "Duty from Reaction (MW)): 21.536107316856004\n", + "Turbine work (MW): -0.9593346445867349\n", + "Mixer outlet temperature (C)): 20.0517142137536\n", + "Compressor outlet temperature (C)): 20.05171421375354\n", + "Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 234.0\n", + "Turbine outlet temperature (C)): 192.87815244243325\n", + "Turbine outlet pressure (Pa)): 3100000.0\n", + "Cooler outlet temperature (C)): 134.0\n", + "Flash outlet temperature (C)): 134.0\n", + "Methanol recovery(%): 60.00443012921678\n", + "annualized capital cost ($/year) = 219790.50447043462\n", + "operating cost ($/year) = 380701687.4964803\n", + "sales ($/year) = 64685201172.198105\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 29074824.816033185\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 336.23\n", + " Total Mole Fraction CH4 dimensionless 2.8373e-06\n", + " Total Mole Fraction CO dimensionless 0.23555\n", + " Total Mole Fraction H2 dimensionless 0.48181\n", + " Total Mole Fraction CH3OH dimensionless 0.28263\n", + " Molar Enthalpy joule / mole -80218.\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 142.57\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3813e+05\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "print(\"Solving with costing...\")\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.381154800Z", + "start_time": "2026-02-20T21:01:09.375269800Z" + }, + "tags": [ + "testing" + ] + }, + "outputs": [], + "source": [ + "# check optimal termination\n", + "assert results2.solver.termination_condition == TerminationCondition.optimal" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Final DOF = 0\n", - "DOF before solve: 0\n", - "\n", - "Solving initial problem...\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.500156800Z", + "start_time": "2026-02-20T21:01:09.382424800Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving optimization problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 975\n", + "Number of nonzeros in inequality constraint Jacobian.: 8\n", + "Number of nonzeros in Lagrangian Hessian.............: 613\n", + "\n", + "Total number of variables............................: 322\n", + " variables with only lower bounds: 43\n", + " variables with lower and upper bounds: 259\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 318\n", + "Total number of inequality constraints...............: 8\n", + " inequality constraints with only lower bounds: 4\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 4\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8492012e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.8402807e+07 2.72e+04 9.71e+01 -1.0 8.82e+06 - 4.99e-02 2.59e-02h 1\n", + " 2 -2.8406592e+07 2.70e+04 9.55e+01 -1.0 8.56e+06 - 7.51e-02 8.58e-03h 1\n", + " 3 -2.8493711e+07 2.29e+04 3.69e+02 -1.0 8.41e+06 - 1.67e-01 1.52e-01h 1\n", + " 4 -2.8493256e+07 2.28e+04 1.20e+04 -1.0 4.60e+06 - 1.00e-01 2.61e-03h 1\n", + " 5 -2.8504483e+07 2.24e+04 1.20e+04 -1.0 4.52e+06 - 2.44e-02 2.38e-02h 1\n", + " 6 -2.8536508e+07 2.16e+04 2.28e+04 -1.0 4.39e+06 - 5.48e-02 6.86e-02h 1\n", + " 7 -2.8537589e+07 2.16e+04 1.35e+05 -1.0 3.94e+06 - 2.56e-01 2.49e-03h 1\n", + " 8 -2.8537637e+07 2.15e+04 6.77e+06 -1.0 1.30e+06 - 4.68e-01 1.17e-04h 1\n", + " 9 -2.8910081e+07 8.51e+04 2.07e+06 -1.0 1.31e+06 - 4.38e-01 9.05e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -2.8914165e+07 7.59e+04 7.45e+06 -1.0 9.51e+04 - 9.00e-01 1.08e-01h 1\n", + " 11 -2.8947367e+07 1.17e+03 1.82e+05 -1.0 8.76e+04 - 9.09e-01 9.90e-01h 1\n", + " 12 -2.8953051e+07 1.08e+01 5.44e+06 -1.0 1.43e+03 -4.0 3.59e-02 9.92e-01h 1\n", + " 13 -2.8953104e+07 4.13e-04 1.09e+05 -1.0 2.11e+01 -4.5 9.90e-01 1.00e+00h 1\n", + " 14 -2.8953015e+07 2.97e-05 8.41e+04 -1.0 3.36e+01 -5.0 9.90e-01 1.00e+00f 1\n", + " 15 -2.8952945e+07 9.83e-05 7.75e+02 -1.0 6.25e+01 -5.4 9.91e-01 1.00e+00f 1\n", + " 16 -2.8952999e+07 1.24e-05 4.07e+00 -1.7 2.92e+01 -5.9 1.00e+00 1.00e+00f 1\n", + " 17 -2.8953295e+07 1.59e-05 3.08e+04 -3.8 1.68e+01 -6.4 9.84e-01 1.00e+00f 1\n", + " 18 -6.7235329e+07 3.98e+05 3.08e+04 -3.8 3.24e+06 - 6.31e-04 1.00e+00f 1\n", + " 19 -6.7161096e+07 3.96e+05 3.08e+04 -3.8 3.97e+05 -6.9 4.51e-04 6.00e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r-6.7161096e+07 3.96e+05 1.00e+03 1.1 0.00e+00 -7.3 0.00e+00 3.70e-07R 5\n", + " 21r-6.0126088e+07 1.13e+05 9.98e+02 1.1 9.47e+08 - 7.54e-04 8.89e-04f 1\n", + " 22 -5.8571015e+07 9.76e+04 1.26e+02 -3.8 1.33e+06 - 2.10e-01 1.37e-01h 1\n", + " 23 -5.8570701e+07 9.76e+04 4.63e+04 -3.8 1.17e+06 - 5.53e-01 3.23e-05h 1\n", + " 24 -5.8606170e+07 8.79e+04 1.84e+05 -3.8 2.62e+06 - 5.56e-03 9.99e-02h 1\n", + " 25 -5.8612488e+07 8.60e+04 7.19e+05 -3.8 2.49e+06 - 2.94e-01 2.08e-02h 1\n", + " 26 -5.8740061e+07 4.93e+04 1.28e+05 -3.8 2.43e+06 - 1.96e-01 4.35e-01h 1\n", + " 27 -5.8740292e+07 4.91e+04 3.28e+07 -3.8 9.94e+05 - 6.54e-01 4.63e-03h 1\n", + " 28 -5.8788497e+07 5.30e+03 1.02e+07 -3.8 9.26e+05 - 8.88e-01 1.00e+00h 1\n", + " 29 -5.8643006e+07 5.29e+03 1.65e+07 -3.8 2.35e+07 - 9.21e-04 1.55e-03h 7\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30 -5.7470132e+07 2.03e+02 1.15e+09 -3.8 2.85e+05 - 9.22e-06 1.00e+00h 1\n", + " 31 -5.7582403e+07 9.77e+00 1.14e+08 -3.8 1.63e+04 - 9.98e-01 1.00e+00h 1\n", + " 32 -7.8527164e+07 1.13e+05 8.45e+06 -3.8 4.35e+06 - 4.64e-01 9.37e-01f 1\n", + " 33 -7.8529326e+07 1.13e+05 8.45e+06 -3.8 5.31e+06 - 7.75e-01 1.16e-04h 1\n", + " 34 -7.9550162e+07 1.33e+05 6.60e+06 -3.8 4.19e+06 - 8.67e-01 2.18e-01h 1\n", + " 35 -7.9541163e+07 1.33e+05 6.57e+06 -3.8 3.58e+05 - 1.65e-03 4.97e-03h 1\n", + " 36 -7.9533059e+07 1.32e+05 6.54e+06 -3.8 1.15e+05 -7.8 1.26e-06 4.40e-03h 1\n", + " 37 -7.9485981e+07 1.29e+05 6.39e+06 -3.8 6.04e+04 -8.3 9.51e-01 2.34e-02h 1\n", + " 38 -7.8379026e+07 4.89e+04 2.42e+06 -3.8 1.52e+05 - 6.47e-01 6.21e-01h 1\n", + " 39 -7.8367473e+07 4.80e+04 2.38e+06 -3.8 5.52e+04 -8.8 3.60e-03 1.70e-02h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 -7.7618174e+07 1.40e+02 3.78e+03 -3.8 3.11e+04 -9.2 1.00e+00 1.00e+00h 1\n", + " 41 -7.7621799e+07 9.06e-01 7.63e-02 -3.8 4.67e+03 - 1.00e+00 1.00e+00h 1\n", + " 42 -7.7699327e+07 1.63e+02 9.22e-03 -3.8 6.11e+04 - 1.00e+00 1.00e+00f 1\n", + " 43 -7.7700167e+07 4.77e-02 2.09e-06 -3.8 1.01e+04 - 1.00e+00 1.00e+00h 1\n", + " 44 -7.7700500e+07 3.88e+00 3.43e+02 -5.7 9.57e+04 - 9.77e-01 1.00e+00h 1\n", + " 45 -7.7700531e+07 4.16e-01 1.40e-03 -5.7 2.26e+04 - 1.00e+00 9.06e-01h 1\n", + " 46 -7.7700531e+07 5.03e-04 3.89e-08 -5.7 9.81e+02 - 1.00e+00 1.00e+00f 1\n", + " 47 -7.7700536e+07 9.48e-04 2.13e-01 -8.6 1.62e+03 - 1.00e+00 9.99e-01h 1\n", + " 48 -7.7700536e+07 5.82e-09 1.08e-10 -8.6 1.88e+00 - 1.00e+00 1.00e+00f 1\n", + " 49 -7.7700536e+07 9.31e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 49\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -1.2012103932708935e+02 -7.7700535938862920e+07\n", + "Dual infeasibility......: 6.9703019509761989e-11 4.5087538392986020e-05\n", + "Constraint violation....: 1.0186340659856796e-10 9.3132257461547852e-09\n", + "Variable bound violation: 5.1274423640279565e-06 5.1274423640279565e-06\n", + "Complementarity.........: 1.4074777602003514e-11 9.1042982063954507e-06\n", + "Overall NLP error.......: 1.0186340659856796e-10 4.5087538392986020e-05\n", + "\n", + "\n", + "Number of objective function evaluations = 63\n", + "Number of objective gradient evaluations = 50\n", + "Number of equality constraint evaluations = 63\n", + "Number of inequality constraint evaluations = 63\n", + "Number of equality constraint Jacobian evaluations = 51\n", + "Number of inequality constraint Jacobian evaluations = 51\n", + "Number of Lagrangian Hessian evaluations = 49\n", + "Total seconds in IPOPT = 0.048\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Optimal solution process results:\n", + "\n", + "\n", + "Extent of reaction: 269.280544787992\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.8500000099999546\n", + "Reactor duty (MW): -51.36357357754579\n", + "Duty from Reaction (MW)): 24.407588579583596\n", + "Turbine work (MW): -1.9904899177794853\n", + "Mixer outlet temperature (C)): 20.05171421375337\n", + "Compressor outlet temperature (C)): 20.051714213753485\n", + "Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 231.85000468716584\n", + "Turbine outlet temperature (C)): 139.85888172675567\n", + "Turbine outlet pressure (Pa)): 1427653.3547820917\n", + "Cooler outlet temperature (C)): 52.56999709299214\n", + "Flash outlet temperature (C)): 134.0\n", + "Methanol recovery(%): 92.80355474657543\n", + "annualized capital cost ($/year) = 235547.18924473305\n", + "operating cost ($/year) = 451663512.6847631\n", + "sales ($/year) = 113381889876.90088\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 77700535.9388629\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 165.54\n", + " Total Mole Fraction CH4 dimensionless 5.7630e-06\n", + " Total Mole Fraction CO dimensionless 0.28706\n", + " Total Mole Fraction H2 dimensionless 0.59587\n", + " Total Mole Fraction CH3OH dimensionless 0.11706\n", + " Molar Enthalpy joule / mole -52313.\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 249.90\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3792e+05\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "opt_res = solver.solve(m, tee=True)\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, the process achieves a much greater revenue as a result of increasing conversion and lowering the inlet temperature to the Flash unit to encourage methanol recovery in the liquid phase. The results show a slight increase in equipment and operating costs from these changes, as well as a small loss of methanol in the exhaust." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1211\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 768\n", - "\n", - "Total number of variables............................: 397\n", - " variables with only lower bounds: 41\n", - " variables with lower and upper bounds: 336\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 397\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 2.79e+02 4.22e+03 -1.0 1.96e+03 - 9.90e-01 9.90e-01h 1\n", - " 2 0.0000000e+00 2.77e+00 3.86e+03 -1.0 2.03e+01 - 9.90e-01 9.90e-01h 1\n", - " 3 0.0000000e+00 7.44e-06 1.01e+03 -1.0 2.01e-01 - 9.90e-01 1.00e+00h 1\n", - "Cannot recompute multipliers for feasibility problem. Error in eq_mult_calculator\n", - "\n", - "Number of Iterations....: 3\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 1.0099088928127792e+05 1.0099088928127792e+05\n", - "Constraint violation....: 2.4014227693119351e-10 7.4444105848670006e-06\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 2.4014227693119351e-10 1.0099088928127792e+05\n", - "\n", - "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.004\n", - "Total CPU secs in NLP function evaluations = 0.001\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - } - ], - "source": [ - "# Build and solve flowsheet\n", - "solver = get_solver() # IPOPT\n", - "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", - "solver.options = optarg\n", - "\n", - "m = ConcreteModel() # create a new model so we may reference 'm' below\n", - "build_model(m) # build flowsheet\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "\n", - "# let the solver determine the tear stream\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "results = solver.solve(m, tee=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:18.405668400Z", - "start_time": "2026-02-20T21:01:18.400079700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:56.084426Z", - "iopub.status.busy": "2026-02-20T21:02:56.084426Z", - "iopub.status.idle": "2026-02-20T21:02:56.086933Z", - "shell.execute_reply": "2026-02-20T21:02:56.086933Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# check optimal termination\n", - "assert results.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.3 Flowsheet Costing and Optimization\n", - "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs, reactor operating costs and utility costs for heating, cooling and electricity. As before, revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, which are updated for new results with the presence of a recycle stream:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:18.574150200Z", - "start_time": "2026-02-20T21:01:18.407172200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:56.088962Z", - "iopub.status.busy": "2026-02-20T21:02:56.088962Z", - "iopub.status.idle": "2026-02-20T21:02:56.217626Z", - "shell.execute_reply": "2026-02-20T21:02:56.217626Z" + "cell_type": "code", + "execution_count": 10, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.508319Z", + "start_time": "2026-02-20T21:01:09.501157500Z" + }, + "tags": [ + "testing" + ] + }, + "outputs": [], + "source": [ + "# testing model results\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "assert value(m.fs.R101.rate_reaction_extent[0, \"R1\"]) == pytest.approx(\n", + " 269.2805, rel=1e-5\n", + ")\n", + "assert value(m.fs.R101.heat_duty[0]) / 1e6 == pytest.approx(-51.3636, rel=1e-5)\n", + "assert value(m.fs.T101.work_isentropic[0]) / 1e6 == pytest.approx(-1.9905, rel=1e-5)\n", + "assert value(m.fs.F101.recovery * 100) == pytest.approx(92.8036, rel=1e-5)\n", + "assert value(m.fs.objective) / 1e6 == pytest.approx(77.7005, rel=1e-5)" + ] }, - "scrolled": false - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 4. Problem Statement - Analyzing Benefit of Recycling Flash Vapor\n", + "\n", + "To increase the efficiency of the process as well as overall methanol production and revenue, we can add a recycle stream to send most of the Flash vapor back to the start of the process. This will reduce methanol loss in the exhaust and increase feed utilization, resulting in increased operating costs and increased production (revenue) at the same conversion. Note that for conversions less than 100%, a simulation with no purge will never converge due to accumulation of gases within the system. Therefore, to ensure we close the mass balance we set a lower bound at 10% purge from the Flash vapor to the exhaust. We expect to see a marginal increase in operating costs due to increased flow, and a much larger increase in overall production resulting in a higher total revenue.\n", + "\n", + "By adding a recycle to the flowsheet, we significantly decrease the tractability of the problem and require a better initial guess. The SequentialDecomposition algorithm automatically determines a stream to *tear*, or use to break the solve loop, and iterates from a set of user-supplied initial guesses until converging on the optimal solution. The code below calls an initialization method to automatically determine the tear stream. See the initialization method of `methanol_flowsheet_w_recycle.py` for further details Sequential Decomposition scheme.\n", + "\n", + "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", + "\n", + "## 4.1. Main Inputs: \n", + "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", + "- Pre-reactor compressor outlet pressure (Pa)\n", + "- Pre-reactor heater outlet temperature (K)\n", + "\n", + "## 4.2. Main Outputs:\n", + "- Extent of reaction (mol/s)\n", + "- Reactor duty (W)\n", + "- Compressor duty (W)\n", + "- Turbine duty (W)\n", + "- Methanol recovery (%)\n", + "- Purge percentage (%)\n", + "- Annual revenue (USD/year)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 11, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.517374100Z", + "start_time": "2026-02-20T21:01:09.509320Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet_recycle.png\")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1227\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 772\n", - "\n", - "Total number of variables............................: 406\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 336\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 406\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8497869e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.9074832e+07 5.76e+04 4.22e+03 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", - " 2 -2.9080637e+07 5.71e+02 3.82e+03 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", - " 3 -2.9080695e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9080695e+07 9.31e-10 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 4\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -4.4953175283791907e+01 -2.9080695361147854e+07\n", - "Dual infeasibility......: 2.4946824403693549e-06 1.6138370562967401e+00\n", - "Constraint violation....: 4.5474735088646412e-12 9.3132257461547852e-10\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 1.6138370562967401e+00\n", - "\n", - "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.005\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 5. Import and Solve Recycle Flowsheet\n", + "## 5.1 Import Pyomo and IDAES Libraries\n", + "As we are rebuilding the model, we need to import require Pyomo and IDAES libraries:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initial solution process results:" - ] + "cell_type": "code", + "execution_count": 12, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.534388600Z", + "start_time": "2026-02-20T21:01:09.517374100Z" + } + }, + "outputs": [], + "source": [ + "import pytest\n", + "import os\n", + "\n", + "# Import Pyomo libraries\n", + "from pyomo.environ import (\n", + " Constraint,\n", + " Objective,\n", + " Var,\n", + " Expression,\n", + " Param,\n", + " ConcreteModel,\n", + " TransformationFactory,\n", + " value,\n", + " maximize,\n", + " units as pyunits,\n", + ")\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.network import Arc, SequentialDecomposition\n", + "\n", + "# Import IDAES core libraries\n", + "from idaes.core import FlowsheetBlock\n", + "from idaes.core.solvers import get_solver\n", + "from idaes.core.util import scaling as iscale\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "from idaes.core.util.initialization import propagate_state\n", + "\n", + "# Import required models\n", + "\n", + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "\n", + "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", + "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", + "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", + "\n", + "from idaes.models.unit_models import (\n", + " Feed,\n", + " Mixer,\n", + " Heater,\n", + " Compressor,\n", + " Turbine,\n", + " StoichiometricReactor,\n", + " Flash,\n", + " Separator as Splitter,\n", + " Product,\n", + ")\n", + "from idaes.models.unit_models.mixer import MomentumMixingType\n", + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core import UnitModelCostingBlock\n", + "from idaes.models.costing.SSLW import SSLWCosting\n", + "import idaes.logger as idaeslog\n", + "\n", + "# import flowsheet functions\n", + "from methanol_flowsheet_w_recycle import (\n", + " build_model,\n", + " set_inputs,\n", + " scale_flowsheet,\n", + " initialize_flowsheet,\n", + " add_costing,\n", + " report,\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\n", - "Extent of reaction: 237.6064180604515\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.22029794711382\n", - "Duty from Reaction (MW)): 21.536645732999325\n", - "Compressor work (MW): -2.5668711294294714e-15\n", - "Turbine work (MW): -0.959378502391431\n", - "Feed Mixer outlet temperature (C)): 20.051714213753144\n", - "Recycle Mixer outlet temperature (C)): 20.056485612776214\n", - "Feed Compressor outlet temperature (C)): 20.0564856127761\n", - "Feed Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.87840947667888\n", - "Turbine outlet pressure (Pa)): 3100000.0\n", - "Cooler outlet temperature (C)): 134.0\n", - "Flash outlet temperature (C)): 134.0\n", - "Purge percentage (amount of vapor vented to exhaust): 99.99 %\n", - "Methanol recovery(%): 60.005984934911716\n", - "annualized capital cost ($/year) = 219794.2325658716\n", - "operating cost ($/year) = 380711692.18369955\n", - "sales ($/year) = 64691081725.72807\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29080695.36114784\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 336.21\n", - " Total Mole Fraction CH4 dimensionless 2.8375e-06\n", - " Total Mole Fraction CO dimensionless 0.23555\n", - " Total Mole Fraction H2 dimensionless 0.48181\n", - " Total Mole Fraction CH3OH dimensionless 0.28263\n", - " Molar Enthalpy joule / mole -80218.\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 142.58\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3813e+05\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:18.582616800Z", - "start_time": "2026-02-20T21:01:18.575222Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:56.219647Z", - "iopub.status.busy": "2026-02-20T21:02:56.219647Z", - "iopub.status.idle": "2026-02-20T21:02:56.222020Z", - "shell.execute_reply": "2026-02-20T21:02:56.222020Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# check optimal termination\n", - "assert results2.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions, including a purge between 10-50% of flash vapor. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:19.012069500Z", - "start_time": "2026-02-20T21:01:18.583630200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:56.224039Z", - "iopub.status.busy": "2026-02-20T21:02:56.224039Z", - "iopub.status.idle": "2026-02-20T21:02:56.614792Z", - "shell.execute_reply": "2026-02-20T21:02:56.614792Z" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5.2 Build and Solve Recycle Flowsheet\n", + "As before, we will first build the flowsheet, set required inputs, initialize and solve a square problem. Recycling methanol to pre-reactor blocks complicates VLE calculations, and limiting VLE calculations to the Flash unit and liquid Product block greatly increases tractability during initialization. All initial feed and unit specifications are identical to the non-recycle case; the Sequential Decomposition algorithm automatically selects the compressor feed as the tear stream and uses \"no recycle\" results as a first guess. In the output below, the solver solves all units and then resolves select blocks with updated inlet results, followed by a full flowsheet solve:" + ] }, - "scrolled": false - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Solving optimization problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 13, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.393968500Z", + "start_time": "2026-02-20T21:01:09.535877100Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unit degrees of freedom\n", + "M101 0\n", + "C101 1\n", + "H101 1\n", + "R101 2\n", + "T101 2\n", + "H102 1\n", + "F101 2\n", + "M102 0\n", + "S101 1\n", + "Total DOF: 24\n", + "DOF after streams specified: 10\n", + "DOF after units specified: 0\n", + "\n", + "Tear Stream:\n", + "fs.s02 : fs.M102.outlet to fs.C101.inlet\n", + "\n", + "Calculation order:\n", + "fs.H2\n", + "fs.M101\n", + "fs.R101\n", + "fs.T101\n", + "fs.H102\n", + "fs.F101\n", + "fs.S101\n", + "fs.EXHAUST\n", + "\n", + "Initial DOF = 0\n", + "Solving fs.H2\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CO\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.C101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.R101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.T101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H102\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.F101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.S101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CH3OH\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.EXHAUST\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M102\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H2\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CO\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.EXHAUST\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CH3OH\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Final DOF = 0\n", + "DOF before solve: 0\n", + "\n", + "Solving initial problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1211\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 768\n", + "\n", + "Total number of variables............................: 397\n", + " variables with only lower bounds: 41\n", + " variables with lower and upper bounds: 336\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 397\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 2.79e+02 4.22e+03 -1.0 1.96e+03 - 9.90e-01 9.90e-01h 1\n", + " 2 0.0000000e+00 2.77e+00 3.86e+03 -1.0 2.03e+01 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 7.44e-06 1.01e+03 -1.0 2.01e-01 - 9.90e-01 1.00e+00h 1\n", + " 4 0.0000000e+00 2.10e-09 9.89e+04 -1.0 1.19e-07 - 9.90e-01 1.00e+00h 1\n", + " 5 0.0000000e+00 2.10e-09 0.00e+00 -1.0 2.51e-08 - 9.91e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 5\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 6.7595993318865371e-14 2.0954757928848267e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 6.7595993318865371e-14 2.0954757928848267e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 6\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.009\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Build and solve flowsheet\n", + "solver = get_solver() # IPOPT\n", + "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", + "solver.options = optarg\n", + "\n", + "m = ConcreteModel() # create a new model so we may reference 'm' below\n", + "build_model(m) # build flowsheet\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "\n", + "# let the solver determine the tear stream\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "results = solver.solve(m, tee=True)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 14, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.403359500Z", + "start_time": "2026-02-20T21:01:12.393968500Z" + }, + "tags": [ + "testing" + ] + }, + "outputs": [], + "source": [ + "# check optimal termination\n", + "assert results.solver.termination_condition == TerminationCondition.optimal" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1236\n", - "Number of nonzeros in inequality constraint Jacobian.: 10\n", - "Number of nonzeros in Lagrangian Hessian.............: 779\n", - "\n", - "Total number of variables............................: 410\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 337\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 405\n", - "Total number of inequality constraints...............: 10\n", - " inequality constraints with only lower bounds: 5\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 5\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8497829e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.8431127e+07 2.74e+04 9.77e+01 -1.0 8.82e+06 - 4.99e-02 1.94e-02h 1\n", - " 2 -2.8430719e+07 2.74e+04 7.81e+02 -1.0 8.52e+06 - 3.76e-02 1.99e-04h 1\n", - " 3 -2.8524903e+07 2.48e+04 1.61e+05 -1.0 6.46e+06 - 2.49e-04 9.25e-02f 1\n", - " 4 -2.8526723e+07 2.48e+04 1.61e+05 -1.0 5.76e+06 - 5.84e-02 9.84e-04h 1\n", - " 5 -2.8554206e+07 2.48e+04 1.60e+05 -1.0 1.49e+07 - 3.32e-03 8.96e-04h 1\n", - " 6 -2.9123967e+07 2.43e+04 1.52e+05 -1.0 1.49e+07 - 1.23e-01 1.84e-02f 1\n", - " 7 -2.9208690e+07 2.43e+04 1.51e+05 -1.0 9.71e+06 - 2.32e-02 2.78e-03h 1\n", - " 8 -3.0003175e+07 2.36e+04 1.08e+06 -1.0 9.31e+06 - 1.92e-01 2.61e-02h 1\n", - " 9 -3.1468200e+07 2.25e+04 1.09e+06 -1.0 8.71e+06 - 6.69e-02 4.91e-02f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -3.1583903e+07 2.24e+04 1.14e+07 -1.0 5.51e+06 - 3.91e-01 3.89e-03h 1\n", - " 11 -4.3112078e+07 3.08e+04 5.71e+06 -1.0 5.49e+06 - 1.57e-01 3.86e-01f 1\n", - " 12 -4.3711661e+07 4.53e+04 5.09e+06 -1.0 3.67e+06 - 8.46e-02 2.88e-02h 1\n", - " 13 -4.3718221e+07 4.53e+04 1.94e+06 -1.0 3.57e+06 - 5.81e-01 3.23e-04h 1\n", - " 14 -4.3760623e+07 4.51e+04 4.16e+07 -1.0 3.56e+06 - 4.25e-01 5.93e-03h 1\n", - " 15 -4.4646398e+07 7.99e+04 5.37e+07 -1.0 3.54e+06 - 6.75e-01 1.23e-01h 4\n", - " 16 -6.6613749e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", - " 17 -6.5999969e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", - " 18 -6.5249518e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", - " 19 -6.4064695e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -6.4051103e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", - " 21 -6.5080976e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", - " 22 -7.5335243e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", - " 23 -7.4658996e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", - " 24 -7.4649764e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", - " 25 -7.4613845e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", - " 26 -7.4421363e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", - " 27 -7.4390154e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n", - " 28 -7.2740081e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", - " 29 -7.2726278e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.2726419e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", - " 31 -8.6665745e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", - " 32 -8.6649468e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", - " 33 -8.6148813e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.44e-02 1.00e+00h 1\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5.3 Flowsheet Costing and Optimization\n", + "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs, reactor operating costs and utility costs for heating, cooling and electricity. As before, revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, which are updated for new results with the presence of a recycle stream:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 34 -8.6163785e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", - " 35 -8.6204319e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", - " 36 -8.6333114e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", - " 37 -8.6713987e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", - " 38 -8.7245785e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", - " 39 -9.0563354e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 40 -9.9476688e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", - " 41 -9.9478624e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", - " 42 -1.0299591e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", - " 43 -1.0299655e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", - " 44 -1.0436244e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", - " 45 -1.0441522e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", - " 46 -1.0438806e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", - " 47 -1.0435495e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", - " 48 -1.0426618e+08 2.01e+03 2.19e+01 -3.8 1.81e+06 - 1.20e-01 1.00e+00h 1\n", - " 49 -1.0426992e+08 2.91e+02 3.40e-01 -3.8 6.45e+04 -13.1 1.00e+00 9.64e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.80e+06 - 5.54e-03 2.57e-01h 1\n", - " 51 -1.0427055e+08 2.92e+02 3.97e+02 -3.8 3.24e+06 - 1.33e-01 1.97e-02h 1\n", - " 52 -1.0427008e+08 1.05e+02 1.15e+05 -3.8 2.71e+04 - 7.76e-04 1.00e+00f 1\n", - " 53 -1.0427044e+08 9.41e+01 7.74e+04 -3.8 4.75e+04 -12.6 1.00e+00 3.26e-01h 2\n", - " 54 -1.0427081e+08 9.98e+01 6.24e+04 -3.8 8.03e+04 -13.1 1.00e+00 1.91e-01h 2\n", - " 55 -1.0427080e+08 8.21e-01 1.24e+00 -3.8 7.52e+04 - 1.00e+00 1.00e+00h 1\n", - " 56 -1.0427114e+08 2.09e+01 2.34e+02 -3.8 3.16e+04 -12.7 1.00e+00 4.65e-01h 2\n" - ] + "cell_type": "code", + "execution_count": 15, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.612557100Z", + "start_time": "2026-02-20T21:01:12.405029Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1227\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 772\n", + "\n", + "Total number of variables............................: 406\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 336\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 406\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8497869e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.9074832e+07 5.76e+04 4.22e+03 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", + " 2 -2.9080637e+07 5.71e+02 3.82e+03 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", + " 3 -2.9080695e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9080695e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9080695e+07 1.16e-09 9.85e+02 -1.0 2.19e-08 - 9.90e-01 1.00e+00h 1\n", + " 6 -2.9080695e+07 9.31e-10 7.17e+04 -1.7 1.59e-08 - 9.91e-01 1.00e+00h 1\n", + " 7 -2.9080695e+07 9.31e-10 2.00e-07 -1.7 2.11e-08 - 1.00e+00 1.00e+00h 1\n", + " 8 -2.9080695e+07 9.31e-10 1.01e-09 -5.7 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + " 9 -2.9080695e+07 9.31e-10 3.69e-13 -8.6 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -2.9080695e+07 9.31e-10 2.90e-13 -10.9 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 10\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -4.4953175283792277e+01 -2.9080695361147840e+07\n", + "Dual infeasibility......: 2.8986503540945592e-13 1.8751682695104163e-07\n", + "Constraint violation....: 4.5474735088646412e-12 9.3132257461547852e-10\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.4052801174098027e-11 9.0909090922898242e-06\n", + "Overall NLP error.......: 1.4052801174098027e-11 9.0909090922898242e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 11\n", + "Number of objective gradient evaluations = 11\n", + "Number of equality constraint evaluations = 11\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 11\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 10\n", + "Total seconds in IPOPT = 0.017\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Initial solution process results:\n", + "\n", + "\n", + "Extent of reaction: 237.60641806045152\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.75\n", + "Reactor duty (MW): -45.22029794711383\n", + "Duty from Reaction (MW)): 21.536645732999325\n", + "Compressor work (MW): -3.72291430867571e-35\n", + "Turbine work (MW): -0.9593785023914099\n", + "Feed Mixer outlet temperature (C)): 20.0517142137532\n", + "Recycle Mixer outlet temperature (C)): 20.056485612776157\n", + "Feed Compressor outlet temperature (C)): 20.056485612776157\n", + "Feed Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 234.0\n", + "Turbine outlet temperature (C)): 192.8784094766802\n", + "Turbine outlet pressure (Pa)): 3100000.0\n", + "Cooler outlet temperature (C)): 134.0\n", + "Flash outlet temperature (C)): 134.0\n", + "Purge percentage (amount of vapor vented to exhaust): 99.99 %\n", + "Methanol recovery(%): 60.0059849349117\n", + "annualized capital cost ($/year) = 219794.23256587266\n", + "operating cost ($/year) = 380711692.1836992\n", + "sales ($/year) = 64691081725.72806\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 29080695.361147825\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 336.21\n", + " Total Mole Fraction CH4 dimensionless 2.8375e-06\n", + " Total Mole Fraction CO dimensionless 0.23555\n", + " Total Mole Fraction H2 dimensionless 0.48181\n", + " Total Mole Fraction CH3OH dimensionless 0.28263\n", + " Molar Enthalpy joule / mole -80218.\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 142.58\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3813e+05\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 57 -1.0427107e+08 4.98e-01 5.37e+00 -3.8 1.61e+04 - 1.00e+00 1.00e+00h 1\n", - " 58 -1.0427121e+08 3.58e+00 1.04e+03 -3.8 1.22e+04 -12.3 1.00e+00 4.79e-01h 2\n", - " 59 -1.0427120e+08 8.56e-03 3.90e+00 -3.8 1.47e+03 - 1.00e+00 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 60 -1.0427265e+08 3.69e+02 2.06e+03 -3.8 6.13e+04 -12.7 1.00e+00 1.00e+00f 1\n", - " 61 -1.0427267e+08 8.82e-03 8.41e-01 -3.8 2.14e+04 - 1.00e+00 1.00e+00h 1\n", - " 62 -1.0427488e+08 8.81e+02 4.71e+03 -3.8 9.30e+04 -13.2 9.57e-01 1.00e+00h 1\n", - " 63 -1.0427489e+08 1.12e-02 8.43e+03 -3.8 2.41e+04 - 4.26e-01 1.00e+00h 1\n", - " 64 -1.0427588e+08 1.77e+02 2.25e+02 -3.8 4.16e+04 -12.8 1.00e+00 1.00e+00h 1\n", - " 65 -1.0427569e+08 7.17e+00 2.18e+02 -3.8 9.45e+03 - 8.56e-01 1.00e+00h 1\n", - " 66 -1.0427569e+08 3.81e-04 1.34e+03 -3.8 7.69e+02 - 3.56e-01 1.00e+00h 1\n", - " 67 -1.0427568e+08 5.99e-04 1.01e+02 -3.8 7.28e+01 - 6.32e-01 1.00e+00h 1\n", - " 68 -1.0427568e+08 5.44e-04 1.32e+02 -3.8 6.86e+01 - 5.69e-01 1.00e+00h 1\n", - " 69 -1.0427569e+08 3.30e-03 2.05e+01 -3.8 2.50e+02 - 6.00e-01 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 70 -1.0427569e+08 1.33e-05 2.19e+01 -3.8 2.05e+02 - 5.83e-01 1.00e+00h 1\n", - " 71 -1.0427569e+08 1.09e-03 3.63e+00 -3.8 5.68e+02 - 5.94e-01 1.00e+00f 1\n", - " 72 -1.0427569e+08 6.75e-04 3.84e+00 -3.8 1.21e+03 - 5.81e-01 1.00e+00h 1\n", - " 73 -1.0427569e+08 6.52e-03 6.49e-01 -3.8 3.03e+03 - 5.80e-01 1.00e+00h 1\n", - " 74 -1.0427570e+08 3.77e-02 6.80e-01 -3.8 7.51e+03 - 5.69e-01 1.00e+00h 1\n", - " 75 -1.0427573e+08 2.57e-01 1.17e-01 -3.8 1.96e+04 - 5.45e-01 1.00e+00h 1\n", - " 76 -1.0427580e+08 2.17e+00 1.46e-01 -3.8 5.66e+04 - 4.91e-01 1.00e+00h 1\n", - " 77 -1.0427608e+08 3.10e+01 6.00e-02 -3.8 2.13e+05 - 3.77e-01 1.00e+00h 1\n", - " 78 -1.0427817e+08 1.76e+03 5.49e-01 -3.8 1.56e+06 - 1.85e-01 1.00e+00h 1\n", - " 79 -1.0427835e+08 1.67e+03 6.12e-01 -3.8 1.75e+06 - 9.50e-01 6.05e-02h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 80 -1.0427838e+08 3.76e-01 2.22e-04 -3.8 9.99e+04 - 1.00e+00 1.00e+00h 1\n", - " 81 -1.0427881e+08 2.24e+00 1.80e+02 -5.7 8.49e+04 - 9.88e-01 1.00e+00h 1\n", - " 82 -1.0427883e+08 9.31e-02 1.16e-03 -5.7 1.69e+04 - 1.00e+00 9.65e-01h 1\n", - " 83 -1.0427883e+08 1.60e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", - " 84 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", - " 85 -1.0427884e+08 5.59e-09 2.35e-13 -8.6 7.18e-01 - 1.00e+00 1.00e+00h 1\n" - ] + "cell_type": "code", + "execution_count": 16, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.622485200Z", + "start_time": "2026-02-20T21:01:12.613467100Z" + }, + "tags": [ + "testing" + ] + }, + "outputs": [], + "source": [ + "# check optimal termination\n", + "assert results2.solver.termination_condition == TerminationCondition.optimal" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 86 -1.0427884e+08 2.79e-09 9.30e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 86\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -1.6119507851267775e+02 -1.0427883997848792e+08\n", - "Dual infeasibility......: 9.2995983076271742e-12 6.0160107413515216e-06\n", - "Constraint violation....: 1.0913936421275139e-10 2.7939677238464355e-09\n", - "Complementarity.........: 1.4067955341342552e-11 9.1007124870068398e-06\n", - "Overall NLP error.......: 1.0913936421275139e-10 9.1007124870068398e-06\n", - "\n", - "\n", - "Number of objective function evaluations = 118\n", - "Number of objective gradient evaluations = 87\n", - "Number of equality constraint evaluations = 118\n", - "Number of inequality constraint evaluations = 118\n", - "Number of equality constraint Jacobian evaluations = 87\n", - "Number of inequality constraint Jacobian evaluations = 87\n", - "Number of Lagrangian Hessian evaluations = 86\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.096\n", - "Total CPU secs in NLP function evaluations = 0.010\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions, including a purge between 10-50% of flash vapor. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:13.760944100Z", + "start_time": "2026-02-20T21:01:12.626378Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving optimization problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1236\n", + "Number of nonzeros in inequality constraint Jacobian.: 10\n", + "Number of nonzeros in Lagrangian Hessian.............: 779\n", + "\n", + "Total number of variables............................: 410\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 337\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 405\n", + "Total number of inequality constraints...............: 10\n", + " inequality constraints with only lower bounds: 5\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 5\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8497829e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.8431127e+07 2.74e+04 9.77e+01 -1.0 8.82e+06 - 4.99e-02 1.94e-02h 1\n", + " 2 -2.8430719e+07 2.74e+04 7.81e+02 -1.0 8.52e+06 - 3.76e-02 1.99e-04h 1\n", + " 3 -2.8524903e+07 2.48e+04 1.61e+05 -1.0 6.46e+06 - 2.49e-04 9.25e-02f 1\n", + " 4 -2.8526723e+07 2.48e+04 1.61e+05 -1.0 5.76e+06 - 5.84e-02 9.84e-04h 1\n", + " 5 -2.8554206e+07 2.48e+04 1.60e+05 -1.0 1.49e+07 - 3.32e-03 8.96e-04h 1\n", + " 6 -2.9123967e+07 2.43e+04 1.52e+05 -1.0 1.49e+07 - 1.23e-01 1.84e-02f 1\n", + " 7 -2.9208690e+07 2.43e+04 1.51e+05 -1.0 9.71e+06 - 2.32e-02 2.78e-03h 1\n", + " 8 -3.0003175e+07 2.36e+04 1.08e+06 -1.0 9.31e+06 - 1.92e-01 2.61e-02h 1\n", + " 9 -3.1468200e+07 2.25e+04 1.09e+06 -1.0 8.71e+06 - 6.69e-02 4.91e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -3.1583903e+07 2.24e+04 1.14e+07 -1.0 5.51e+06 - 3.91e-01 3.89e-03h 1\n", + " 11 -4.3112078e+07 3.08e+04 5.71e+06 -1.0 5.49e+06 - 1.57e-01 3.86e-01f 1\n", + " 12 -4.3711661e+07 4.53e+04 5.09e+06 -1.0 3.67e+06 - 8.46e-02 2.88e-02h 1\n", + " 13 -4.3718221e+07 4.53e+04 1.94e+06 -1.0 3.57e+06 - 5.81e-01 3.23e-04h 1\n", + " 14 -4.3760623e+07 4.51e+04 4.16e+07 -1.0 3.56e+06 - 4.25e-01 5.93e-03h 1\n", + " 15 -4.4646398e+07 7.99e+04 5.37e+07 -1.0 3.54e+06 - 6.75e-01 1.23e-01h 4\n", + " 16 -6.6613710e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", + " 17 -6.5999923e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", + " 18 -6.5249462e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", + " 19 -6.4064651e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 -6.4051060e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", + " 21 -6.5080931e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", + " 22 -7.5335226e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", + " 23 -7.4658976e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", + " 24 -7.4649744e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", + " 25 -7.4613824e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", + " 26 -7.4421345e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", + " 27 -7.4390136e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n", + " 28 -7.2740056e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", + " 29 -7.2726253e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30 -7.2726394e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", + " 31 -8.6665441e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", + " 32 -8.6649164e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", + " 33 -8.6148490e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.45e-02 1.00e+00h 1\n", + " 34 -8.6163461e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", + " 35 -8.6203995e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", + " 36 -8.6332790e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", + " 37 -8.6713663e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", + " 38 -8.7245413e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", + " 39 -9.0562979e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 -9.9476648e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", + " 41 -9.9478583e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", + " 42 -1.0299584e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", + " 43 -1.0299648e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", + " 44 -1.0436243e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", + " 45 -1.0441521e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", + " 46 -1.0438805e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", + " 47 -1.0435494e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", + " 48 -1.0426618e+08 2.01e+03 2.19e+01 -3.8 1.81e+06 - 1.20e-01 1.00e+00h 1\n", + " 49 -1.0426992e+08 2.91e+02 3.40e-01 -3.8 6.45e+04 -13.1 1.00e+00 9.64e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.79e+06 - 5.54e-03 2.58e-01h 1\n", + " 51 -1.0427055e+08 2.93e+02 3.98e+02 -3.8 3.24e+06 - 1.33e-01 1.93e-02h 1\n", + " 52 -1.0427009e+08 1.02e+02 1.15e+05 -3.8 2.79e+04 - 7.85e-04 1.00e+00f 1\n", + " 53 -1.0427045e+08 9.18e+01 7.72e+04 -3.8 4.68e+04 -12.6 1.00e+00 3.29e-01h 2\n", + " 54 -1.0427082e+08 9.84e+01 6.22e+04 -3.8 8.09e+04 -13.1 1.00e+00 1.92e-01h 2\n", + " 55 -1.0427081e+08 7.24e-01 1.18e+00 -3.8 7.63e+04 - 1.00e+00 1.00e+00h 1\n", + " 56 -1.0427115e+08 2.08e+01 2.49e+02 -3.8 3.14e+04 -12.7 1.00e+00 4.68e-01h 2\n", + " 57 -1.0427108e+08 6.33e-01 6.20e+00 -3.8 1.65e+04 - 1.00e+00 1.00e+00h 1\n", + " 58 -1.0427122e+08 3.69e+00 9.97e+02 -3.8 1.26e+04 -12.3 1.00e+00 4.66e-01h 2\n", + " 59 -1.0427122e+08 5.22e-05 1.89e-01 -3.8 1.65e+03 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60 -1.0428563e+08 3.80e+04 2.56e+04 -3.8 3.34e+06 - 7.06e-02 1.80e-01f 1\n", + " 61 -1.0428562e+08 3.78e+04 2.55e+04 -3.8 4.32e+05 - 2.18e-02 5.77e-03h 1\n", + " 62 -1.0428017e+08 3.77e+04 2.54e+04 -3.8 1.25e+07 -12.7 7.48e-05 2.34e-03h 9\n", + " 63 -1.0427440e+08 3.74e+04 2.52e+04 -3.8 3.76e+06 -12.3 5.74e-03 7.81e-03h 8\n", + " 64 -1.0427481e+08 3.74e+04 2.52e+04 -3.8 4.44e+05 -9.2 2.60e-01 1.25e-03h 1\n", + " 65 -1.0427459e+08 3.69e+04 2.49e+04 -3.8 4.18e+05 -9.7 3.22e-03 1.13e-02h 1\n", + " 66 -1.0427441e+08 3.69e+04 2.49e+04 -3.8 7.62e+08 -10.1 6.54e-09 7.13e-08f 11\n", + " 67 -1.0427290e+08 3.69e+04 2.49e+04 -3.8 8.98e+05 -9.7 1.79e-03 4.88e-04h 12\n", + " 68 -1.0427211e+08 3.69e+04 2.49e+04 -3.8 7.85e+05 -9.3 1.13e-03 4.88e-04h 12\n", + " 69 -1.0427200e+08 3.69e+04 2.49e+04 -3.8 1.16e+06 -9.8 2.41e-03 2.60e-05h 16\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70 -1.0427193e+08 3.69e+04 2.49e+04 -3.8 4.05e+05 -9.3 2.02e-01 2.35e-04h 5\n", + " 71 -1.0426925e+08 3.69e+04 2.49e+04 -3.8 1.03e+06 -9.8 6.63e-04 6.63e-04s 22\n", + " 72 -1.0425036e+08 3.57e+04 2.41e+04 -3.8 3.87e+05 -9.4 3.17e-02 3.17e-02s 22\n", + " 73 -1.0424520e+08 3.57e+04 2.41e+04 -3.8 1.58e+06 -9.9 9.56e-04 9.56e-04s 22\n", + " 74 -1.0421332e+08 3.51e+04 2.37e+04 -3.8 7.70e+05 -9.4 1.52e-02 1.52e-02s 22\n", + " 75 -1.0409397e+08 3.47e+04 2.34e+04 -3.8 2.08e+06 -9.9 1.36e-02 1.36e-02s 22\n", + " 76 -1.0387838e+08 2.73e+04 1.81e+04 -3.8 3.89e+05 -9.5 2.45e-01 2.45e-01s 22\n", + " 77 -1.0368499e+08 2.52e+04 1.67e+04 -3.8 5.49e+05 -10.0 8.21e-02 8.21e-02s 22\n", + " 78 -1.0298419e+08 2.17e+04 1.42e+04 -3.8 8.63e+05 -10.4 1.56e-01 1.56e-01s 22\n", + " 79 -1.0163132e+08 1.11e+04 6.55e+03 -3.8 5.27e+05 -10.9 6.20e-01 6.20e-01s 22\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80 -1.0194825e+08 1.09e+03 5.66e+02 -3.8 8.31e+04 -11.4 9.54e-01 9.54e-01s 22\n", + " 81 -1.0310109e+08 8.15e+02 4.00e+02 -3.8 5.53e+05 -11.9 2.90e-01 2.90e-01s 22\n", + " 82r-1.0310109e+08 8.15e+02 1.00e+03 -1.6 0.00e+00 -12.4 0.00e+00 0.00e+00R 1\n", + " 83r-1.0310498e+08 2.20e+02 3.18e+03 -1.6 1.50e+03 -4.0 2.25e-03 9.91e-04f 1\n", + " 84r-1.0303151e+08 8.00e+01 3.93e+03 -1.6 8.93e+06 - 3.97e-03 2.67e-03f 1\n", + " 85r-1.0297296e+08 3.79e+01 4.49e+03 -1.6 2.18e+06 - 9.30e-03 7.81e-03f 1\n", + " 86r-1.0295114e+08 8.32e+01 6.01e+03 -1.6 1.88e+06 - 2.57e-02 1.93e-02f 1\n", + " 87r-1.0295645e+08 6.88e+02 7.54e+03 -1.6 1.99e+06 - 6.81e-02 5.54e-02f 1\n", + " 88r-1.0295646e+08 5.58e+02 2.74e+04 -1.6 1.22e+02 -4.5 4.65e-01 1.86e-01f 1\n", + " 89r-1.0253465e+08 4.33e+02 1.34e+04 -1.6 4.11e+05 - 9.66e-01 2.98e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r-1.0417196e+08 5.86e+02 1.34e+04 -1.6 6.16e+06 - 3.39e-01 8.07e-02f 1\n", + " 91r-1.0366409e+08 6.25e+02 2.53e+03 -1.6 1.19e+05 - 2.93e-01 1.00e+00f 1\n", + " 92r-1.0364727e+08 2.09e+02 3.79e+02 -1.6 5.53e+01 -5.0 1.00e+00 6.66e-01h 1\n", + " 93r-1.0365950e+08 8.11e-03 1.47e+00 -1.6 6.58e+01 -5.4 1.00e+00 1.00e+00f 1\n", + " 94r-1.0367534e+08 2.57e-01 2.93e+03 -2.4 2.27e+02 -5.9 1.00e+00 8.08e-01f 1\n", + " 95r-1.0369165e+08 1.08e-01 3.47e+03 -2.4 2.04e+02 -6.4 1.00e+00 6.02e-01f 1\n", + " 96r-1.0369511e+08 2.28e-03 3.84e+00 -2.4 4.36e+01 -6.9 1.00e+00 1.00e+00f 1\n", + " 97r-1.0369311e+08 1.00e+03 1.22e+02 -2.4 1.53e+05 - 7.06e-01 1.00e+00f 1\n", + " 98r-1.0369133e+08 5.34e-02 6.47e-02 -2.4 6.89e+01 -7.3 1.00e+00 1.00e+00h 1\n", + " 99r-1.0364795e+08 1.01e+02 3.37e+02 -3.6 3.26e+04 - 6.54e-01 7.41e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r-1.0309823e+08 3.06e+01 6.46e+02 -3.6 1.67e+05 - 9.13e-01 9.87e-01f 1\n", + " 101r-1.0314314e+08 3.32e-01 6.34e+00 -3.6 1.21e+04 - 1.00e+00 1.00e+00f 1\n", + " 102r-1.0314312e+08 2.74e-05 1.09e-02 -3.6 3.60e+00 -7.8 1.00e+00 1.00e+00h 1\n", + " 103 -1.0319578e+08 9.61e-05 4.23e+01 -3.8 8.11e+03 - 9.97e-01 1.00e+00F 1\n", + " 104 -1.0413984e+08 4.94e+00 1.28e+03 -3.8 1.56e+06 - 8.31e-01 1.60e-01f 1\n", + " 105 -1.0414099e+08 4.85e+00 1.30e+03 -3.8 4.79e+04 - 1.33e-01 1.69e-02h 1\n", + " 106 -1.0417962e+08 1.56e+01 1.28e+03 -3.8 8.29e+06 - 9.95e-04 1.31e-02f 1\n", + " 107 -1.0415007e+08 1.55e+01 1.39e+01 -3.8 9.94e+04 - 9.52e-01 1.00e+00h 1\n", + " 108 -1.0417530e+08 2.20e+02 1.98e-01 -3.8 6.87e+04 - 9.90e-01 9.64e-01h 1\n", + " 109 -1.0428156e+08 1.32e+04 8.97e+01 -3.8 3.02e+06 - 7.12e-01 1.63e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110 -1.0426214e+08 2.88e+02 4.67e+01 -3.8 2.97e+05 - 5.07e-01 1.00e+00h 1\n", + " 111 -1.0426904e+08 1.71e+03 4.37e+01 -3.8 9.53e+06 - 4.40e-02 1.74e-01H 1\n", + " 112 -1.0427745e+08 1.25e+03 2.84e+00 -3.8 1.36e+06 - 9.80e-01 5.51e-01h 1\n", + " 113 -1.0427831e+08 4.62e+02 1.37e-03 -3.8 6.34e+05 - 1.00e+00 1.00e+00h 1\n", + " 114 -1.0427838e+08 1.66e+00 5.16e-06 -3.8 1.36e+04 - 1.00e+00 1.00e+00h 1\n", + " 115 -1.0427881e+08 2.67e+00 2.14e+02 -5.7 8.92e+04 - 9.86e-01 1.00e+00h 1\n", + " 116 -1.0427883e+08 1.12e-01 1.14e-03 -5.7 1.75e+04 - 1.00e+00 9.65e-01h 1\n", + " 117 -1.0427883e+08 2.06e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", + " 118 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", + " 119 -1.0427884e+08 3.73e-09 2.76e-13 -8.6 7.19e-01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120 -1.0427884e+08 1.86e-09 9.31e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 120\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -1.6119507851267775e+02 -1.0427883997848789e+08\n", + "Dual infeasibility......: 9.3067037146559845e-12 6.0206073060194729e-06\n", + "Constraint violation....: 1.0913936421275139e-10 1.8626451492309570e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 1.4067955341264719e-11 9.1007124869564871e-06\n", + "Overall NLP error.......: 1.0913936421275139e-10 9.1007124869564871e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 255\n", + "Number of objective gradient evaluations = 101\n", + "Number of equality constraint evaluations = 255\n", + "Number of inequality constraint evaluations = 255\n", + "Number of equality constraint Jacobian evaluations = 121\n", + "Number of inequality constraint Jacobian evaluations = 121\n", + "Number of Lagrangian Hessian evaluations = 120\n", + "Total seconds in IPOPT = 0.174\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1236\n", + "Number of nonzeros in inequality constraint Jacobian.: 10\n", + "Number of nonzeros in Lagrangian Hessian.............: 779\n", + "\n", + "Total number of variables............................: 410\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 337\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 405\n", + "Total number of inequality constraints...............: 10\n", + " inequality constraints with only lower bounds: 5\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 5\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -1.0301714e+08 2.98e+05 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -1.0365412e+08 1.32e+05 4.21e+01 -1.0 8.57e+04 - 8.59e-01 5.52e-01h 1\n", + " 2 -1.0410108e+08 5.26e+04 7.56e+03 -1.0 5.09e+04 - 9.61e-01 5.97e-01h 1\n", + " 3 -1.0413437e+08 2.06e+04 2.27e+02 -1.0 2.41e+04 - 9.37e-01 6.07e-01h 1\n", + " 4 -1.0424131e+08 1.93e+02 5.00e+03 -1.0 1.94e+05 - 9.87e-01 9.90e-01h 1\n", + " 5 -1.0420077e+08 9.43e+00 3.43e+03 -1.0 1.40e+05 - 9.11e-01 9.91e-01h 1\n", + " 6 -1.0416592e+08 2.19e+01 9.98e+05 -1.0 7.17e+05 - 7.26e-01 1.56e-02f 7\n", + " 7 -1.0366377e+08 9.17e+01 5.74e+05 -1.0 4.94e+05 - 5.51e-01 1.00e+00H 1\n", + " 8 -1.0363147e+08 9.84e+01 7.49e+06 -1.0 9.50e+05 - 9.90e-01 1.56e-02f 7\n", + " 9 -1.0252180e+08 7.86e+02 3.75e+04 -1.0 1.53e+06 - 7.68e-01 1.00e+00F 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -1.0190033e+08 6.00e+00 1.87e+03 -1.0 2.37e+05 - 1.00e+00 1.00e+00H 1\n", + " 11 -1.0201665e+08 1.13e+01 8.51e+01 -1.0 1.34e+05 - 1.00e+00 1.00e+00H 1\n", + " 12 -1.0416792e+08 1.89e+04 2.50e+06 -2.5 1.28e+06 - 3.10e-01 5.67e-01f 1\n", + " 13 -1.0432990e+08 7.37e+04 1.94e+05 -2.5 1.61e+06 - 8.21e-01 6.69e-01h 1\n", + " 14 -1.0425973e+08 1.27e+02 1.47e+03 -2.5 4.32e+04 - 1.00e+00 1.00e+00h 1\n", + " 15 -1.0426575e+08 1.07e+01 1.87e-01 -2.5 5.16e+04 - 1.00e+00 1.00e+00h 1\n", + " 16 -1.0427763e+08 2.48e+01 2.62e+01 -3.8 6.19e+04 - 1.00e+00 1.00e+00h 1\n", + " 17 -1.0427797e+08 9.99e+01 2.44e-03 -3.8 3.85e+05 - 1.00e+00 1.00e+00h 1\n", + " 18 -1.0427790e+08 1.94e+00 1.79e-05 -3.8 5.18e+04 - 1.00e+00 1.00e+00h 1\n", + " 19 -1.0427873e+08 8.25e+00 5.26e+02 -5.7 1.32e+05 - 9.65e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 -1.0427883e+08 1.02e+00 6.20e-03 -5.7 6.34e+04 - 1.00e+00 9.13e-01h 1\n", + " 21 -1.0427883e+08 2.22e-03 7.11e-08 -5.7 2.00e+03 - 1.00e+00 1.00e+00f 1\n", + " 22 -1.0427884e+08 2.66e-03 1.10e-05 -8.6 3.26e+03 - 1.00e+00 1.00e+00h 1\n", + " 23 -1.0427884e+08 1.16e-08 1.87e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", + " 24 -1.0427884e+08 4.19e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 24\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -7.4466968713582887e+01 -1.0427883997850095e+08\n", + "Dual infeasibility......: 2.0257749632681967e-11 2.8367673194755198e-05\n", + "Constraint violation....: 1.3824319466948509e-10 4.1909515857696533e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 6.5249453183278187e-12 9.1371213367822650e-06\n", + "Overall NLP error.......: 1.3824319466948509e-10 2.8367673194755198e-05\n", + "\n", + "\n", + "Number of objective function evaluations = 52\n", + "Number of objective gradient evaluations = 25\n", + "Number of equality constraint evaluations = 52\n", + "Number of inequality constraint evaluations = 52\n", + "Number of equality constraint Jacobian evaluations = 25\n", + "Number of inequality constraint Jacobian evaluations = 25\n", + "Number of Lagrangian Hessian evaluations = 24\n", + "Total seconds in IPOPT = 0.026\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Optimal solution process results:\n", + "\n", + "\n", + "Extent of reaction: 311.3069854950048\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : -0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.8500000099996615\n", + "Reactor duty (MW): -59.34022107299101\n", + "Duty from Reaction (MW)): 28.216865165267237\n", + "Compressor work (MW): -4.7980486241206324e-24\n", + "Turbine work (MW): -2.491301208383993\n", + "Feed Mixer outlet temperature (C)): 20.051714213753485\n", + "Recycle Mixer outlet temperature (C)): 41.54321437801826\n", + "Feed Compressor outlet temperature (C)): 41.54321437801826\n", + "Feed Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 231.85000478422364\n", + "Turbine outlet temperature (C)): 141.50037862882186\n", + "Turbine outlet pressure (Pa)): 1487177.2483574806\n", + "Cooler outlet temperature (C)): 52.56999699077659\n", + "Flash outlet temperature (C)): 134.0\n", + "Purge percentage (amount of vapor vented to exhaust): 9.999999000026644 %\n", + "Methanol recovery(%): 92.05882105498134\n", + "annualized capital cost ($/year) = 259559.90821288814\n", + "operating cost ($/year) = 525130020.70956033\n", + "sales ($/year) = 140033684437.28268\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 104278839.97850095\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 22.743\n", + " Total Mole Fraction CH4 dimensionless 4.1946e-05\n", + " Total Mole Fraction CO dimensionless 0.24155\n", + " Total Mole Fraction H2 dimensionless 0.64134\n", + " Total Mole Fraction CH3OH dimensionless 0.11706\n", + " Molar Enthalpy joule / mole -47286.\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 308.65\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3792e+05\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", + "m.fs.S101.split_fraction_lb = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", + ") # min 10% purge\n", + "m.fs.S101.split_fraction_ub = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", + ") # max 50% purge\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "\n", + "# Pass 1: smoothed VLE transition\n", + "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "\n", + "\n", + "solver.options[\"max_iter\"] = 200\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "# Pass 2: restore default smoothness\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, recycling methanol and gases from the flash vapor achieves much greater methanol production, and process cost increases are small compared to the increase in revenue. Note that the reaction conversion and flash inlet temperature did not change, and we obtain the same percentage methanol recovery. We can see in the stream tables that far more of the inlet material exits as methanol than in the non-recycle process (note that we do not have a mole balance due to the reaction stoichiometry). The results show a slight increase in equipment and operating costs from increased throughput on each unit." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n" - ] + "cell_type": "code", + "execution_count": 18, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:13.770912800Z", + "start_time": "2026-02-20T21:01:13.761945900Z" + }, + "tags": [ + "testing" + ] + }, + "outputs": [], + "source": [ + "# testing model results\n", + "assert value(m.fs.R101.rate_reaction_extent[0, \"R1\"]) == pytest.approx(\n", + " 311.3070, rel=1e-5\n", + ")\n", + "assert value(m.fs.R101.heat_duty[0]) / 1e6 == pytest.approx(-59.3402, rel=1e-5)\n", + "assert value(m.fs.C101.work_mechanical[0]) / 1e6 == pytest.approx(0, abs=1e-5)\n", + "assert value(m.fs.T101.work_isentropic[0]) / 1e6 == pytest.approx(-2.4913, rel=1e-5)\n", + "assert value(m.fs.F101.recovery * 100) == pytest.approx(92.0589, rel=1e-5)\n", + "assert value(m.fs.S101.split_fraction[0, \"purge\"] * 100) == pytest.approx(\n", + " 10.0000, rel=1e-5\n", + ")\n", + "assert value(m.fs.objective) / 1e6 == pytest.approx(104.2789, rel=1e-5)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1236\n", - "Number of nonzeros in inequality constraint Jacobian.: 10\n", - "Number of nonzeros in Lagrangian Hessian.............: 779\n", - "\n", - "Total number of variables............................: 410\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 337\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 405\n", - "Total number of inequality constraints...............: 10\n", - " inequality constraints with only lower bounds: 5\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 5\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -1.0301714e+08 2.98e+05 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -1.0365412e+08 1.32e+05 4.21e+01 -1.0 8.57e+04 - 8.59e-01 5.52e-01h 1\n", - " 2 -1.0410108e+08 5.26e+04 7.56e+03 -1.0 5.09e+04 - 9.61e-01 5.97e-01h 1\n", - " 3 -1.0413437e+08 2.06e+04 2.27e+02 -1.0 2.41e+04 - 9.37e-01 6.07e-01h 1\n", - " 4 -1.0424131e+08 1.93e+02 5.00e+03 -1.0 1.94e+05 - 9.87e-01 9.90e-01h 1\n", - " 5 -1.0420077e+08 9.43e+00 3.43e+03 -1.0 1.40e+05 - 9.11e-01 9.91e-01h 1\n", - " 6 -1.0416592e+08 2.19e+01 9.98e+05 -1.0 7.17e+05 - 7.26e-01 1.56e-02f 7\n", - " 7 -1.0366377e+08 9.17e+01 5.74e+05 -1.0 4.94e+05 - 5.51e-01 1.00e+00H 1\n", - " 8 -1.0363147e+08 9.84e+01 7.49e+06 -1.0 9.50e+05 - 9.90e-01 1.56e-02f 7\n", - " 9 -1.0252180e+08 7.86e+02 3.75e+04 -1.0 1.53e+06 - 7.68e-01 1.00e+00F 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -1.0190033e+08 6.00e+00 1.87e+03 -1.0 2.37e+05 - 1.00e+00 1.00e+00H 1\n", - " 11 -1.0201665e+08 1.13e+01 8.51e+01 -1.0 1.34e+05 - 1.00e+00 1.00e+00H 1\n", - " 12 -1.0416792e+08 1.89e+04 2.50e+06 -2.5 1.28e+06 - 3.10e-01 5.67e-01f 1\n", - " 13 -1.0432990e+08 7.37e+04 1.94e+05 -2.5 1.61e+06 - 8.21e-01 6.69e-01h 1\n", - " 14 -1.0425973e+08 1.27e+02 1.47e+03 -2.5 4.32e+04 - 1.00e+00 1.00e+00h 1\n", - " 15 -1.0426575e+08 1.07e+01 1.87e-01 -2.5 5.16e+04 - 1.00e+00 1.00e+00h 1\n", - " 16 -1.0427763e+08 2.48e+01 2.62e+01 -3.8 6.19e+04 - 1.00e+00 1.00e+00h 1\n", - " 17 -1.0427797e+08 9.99e+01 2.44e-03 -3.8 3.85e+05 - 1.00e+00 1.00e+00h 1\n", - " 18 -1.0427790e+08 1.94e+00 1.79e-05 -3.8 5.18e+04 - 1.00e+00 1.00e+00h 1\n", - " 19 -1.0427873e+08 8.25e+00 5.26e+02 -5.7 1.32e+05 - 9.65e-01 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -1.0427883e+08 1.02e+00 6.20e-03 -5.7 6.34e+04 - 1.00e+00 9.13e-01h 1\n", - " 21 -1.0427883e+08 2.22e-03 7.11e-08 -5.7 2.00e+03 - 1.00e+00 1.00e+00f 1\n", - " 22 -1.0427884e+08 2.66e-03 1.10e-05 -8.6 3.26e+03 - 1.00e+00 1.00e+00h 1\n", - " 23 -1.0427884e+08 1.16e-08 1.82e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", - " 24 -1.0427884e+08 3.14e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 24\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -7.4466968713582915e+01 -1.0427883997850099e+08\n", - "Dual infeasibility......: 2.0257749320973842e-11 2.8367672758258825e-05\n", - "Constraint violation....: 1.3824319466948509e-10 3.1432136893272400e-09\n", - "Complementarity.........: 6.5249453183277711e-12 9.1371213367821990e-06\n", - "Overall NLP error.......: 1.3824319466948509e-10 2.8367672758258825e-05\n", - "\n", - "\n", - "Number of objective function evaluations = 52\n", - "Number of objective gradient evaluations = 25\n", - "Number of equality constraint evaluations = 52\n", - "Number of inequality constraint evaluations = 52\n", - "Number of equality constraint Jacobian evaluations = 25\n", - "Number of inequality constraint Jacobian evaluations = 25\n", - "Number of Lagrangian Hessian evaluations = 24\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.020\n", - "Total CPU secs in NLP function evaluations = 0.007\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 6. Summary\n", + "The present example demonstrates building, initializing and optimizing a methanol synthesis problem in IDAES. The imported scripts implement models from the IDAES pre-defined unit model library, the IDAES Property and Reaction Framework, targeted thermophysical properties for specific unit blocks, Pyomo's Sequential Decomposition methods, the IDAES Costing Framework for capital cost calculations, and integration of custom surrogate expressions for operating cost calculations. The methanol synthesis flowsheet methods may be imported into any external script, and users may build, initialize and optimize the entire model via the `main()` method in each flowsheet." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal solution process results:\n", - "\n", - "\n", - "Extent of reaction: 311.30698549500477\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.8500000099996615\n", - "Reactor duty (MW): -59.340221072991014\n", - "Duty from Reaction (MW)): 28.216865165267233\n", - "Compressor work (MW): 1.2861669211016399e-24\n", - "Turbine work (MW): -2.4913012083840025\n", - "Feed Mixer outlet temperature (C)): 20.05171421375354\n", - "Recycle Mixer outlet temperature (C)): 41.54321437801775\n", - "Feed Compressor outlet temperature (C)): 41.54321437801792\n", - "Feed Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 231.85000478422364\n", - "Turbine outlet temperature (C)): 141.50037862882152\n", - "Turbine outlet pressure (Pa)): 1487177.2483574792\n", - "Cooler outlet temperature (C)): 52.56999699077659\n", - "Flash outlet temperature (C)): 134.0\n", - "Purge percentage (amount of vapor vented to exhaust): 9.999999000026644 %\n", - "Methanol recovery(%): 92.05882105498138\n", - "annualized capital cost ($/year) = 259559.90821288762\n", - "operating cost ($/year) = 525130020.7095608\n", - "sales ($/year) = 140033684437.2827\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 104278839.97850098\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 22.743\n", - " Total Mole Fraction CH4 dimensionless 4.1946e-05\n", - " Total Mole Fraction CO dimensionless 0.24155\n", - " Total Mole Fraction H2 dimensionless 0.64134\n", - " Total Mole Fraction CH3OH dimensionless 0.11706\n", - " Molar Enthalpy joule / mole -47286.\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 308.65\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3792e+05\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n" - ] + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:13.775587500Z", + "start_time": "2026-02-20T21:01:13.771970400Z" + } + }, + "outputs": [], + "source": [] } - ], - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", - "m.fs.S101.split_fraction_lb = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", - ") # min 10% purge\n", - "m.fs.S101.split_fraction_ub = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", - ") # max 50% purge\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "\n", - "# Pass 1: smoothed VLE transition\n", - "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "# Pass 2: restore default smoothness\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, recycling methanol and gases from the flash vapor achieves much greater methanol production, and process cost increases are small compared to the increase in revenue. Note that the reaction conversion and flash inlet temperature did not change, and we obtain the same percentage methanol recovery. We can see in the stream tables that far more of the inlet material exits as methanol than in the non-recycle process (note that we do not have a mole balance due to the reaction stoichiometry). The results show a slight increase in equipment and operating costs from increased throughput on each unit." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:19.020892900Z", - "start_time": "2026-02-20T21:01:19.013109200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:56.616850Z", - "iopub.status.busy": "2026-02-20T21:02:56.616850Z", - "iopub.status.idle": "2026-02-20T21:02:56.621454Z", - "shell.execute_reply": "2026-02-20T21:02:56.621454Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# testing model results\n", - "assert value(m.fs.R101.rate_reaction_extent[0, \"R1\"]) == pytest.approx(\n", - " 311.3070, rel=1e-5\n", - ")\n", - "assert value(m.fs.R101.heat_duty[0]) / 1e6 == pytest.approx(-59.3402, rel=1e-5)\n", - "assert value(m.fs.C101.work_mechanical[0]) / 1e6 == pytest.approx(0, abs=1e-5)\n", - "assert value(m.fs.T101.work_isentropic[0]) / 1e6 == pytest.approx(-2.4913, rel=1e-5)\n", - "assert value(m.fs.F101.recovery * 100) == pytest.approx(92.0589, rel=1e-5)\n", - "assert value(m.fs.S101.split_fraction[0, \"purge\"] * 100) == pytest.approx(\n", - " 10.0000, rel=1e-5\n", - ")\n", - "assert value(m.fs.objective) / 1e6 == pytest.approx(104.2789, rel=1e-5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 6. Summary\n", - "The present example demonstrates building, initializing and optimizing a methanol synthesis problem in IDAES. The imported scripts implement models from the IDAES pre-defined unit model library, the IDAES Property and Reaction Framework, targeted thermophysical properties for specific unit blocks, Pyomo's Sequential Decomposition methods, the IDAES Costing Framework for capital cost calculations, and integration of custom surrogate expressions for operating cost calculations. The methanol synthesis flowsheet methods may be imported into any external script, and users may build, initialize and optimize the entire model via the `main()` method in each flowsheet." - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:19.024997Z", - "start_time": "2026-02-20T21:01:19.020892900Z" + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.11" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_usr.ipynb b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_usr.ipynb index ab56e88f..a53c5103 100644 --- a/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_usr.ipynb +++ b/idaes_examples/notebooks/docs/flowsheets/methanol_synthesis_usr.ipynb @@ -1,4167 +1,2321 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:16.618908800Z", - "start_time": "2026-02-20T21:01:16.610747300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:30.225238Z", - "iopub.status.busy": "2026-02-20T21:02:30.224224Z", - "iopub.status.idle": "2026-02-20T21:02:30.228354Z", - "shell.execute_reply": "2026-02-20T21:02:30.228354Z" - }, - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Methanol Synthesis Flowsheet Example\n", - "Maintainer: Brandon Paul \n", - "Author: Brandon Paul \n", - "Updated: 2023-06-01 \n", - "\n", - "The purpose of this notebook is to demonstrate flowsheet synthesis integrating IDAES modeling tools, including the Unit Model Library, Property and Reaction Framework, IDAES scaling tools and the Process Costing Framework. The example leverages imports from external flowsheet scripts, and demonstrates implementation of separate VLE and vapor-only property packages to reduce model complexity where applicable.\n", - "\n", - "## Simplified Hydrogen Reformation System\n", - "\n", - "This example demonstrates a steady-state model of methanol synthesis from hydrogen and carbon monoxide. To simulate relevant natural gas components, the reactant vapors are mixed stoichiometrically and brought to optimal reaction conditions prior to entering the gas-phase reactor. Vapor liquid equilibrium is mainly applicable in the post-reactor Flash unit for methanol recovery, and is accounted for by separate vapor and VLE thermophysical property packages. See `methanol_flowsheet.py` for more information on how to assemble the flowsheet, as well as [idaes_examples.mod.methanol.methanol_ideal_VLE.py](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_VLE.py), [idaes_examples.mod.methanol.methanol_ideal_vapor](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_vapor.py) and [idaes_examples.mod.methanol.methanol_reactions](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_reactions.py) for more information on the thermophyscial and reaction properties.\n", - "\n", - "This example is a reasonable approximation for gas-phase methanol synthesis systems and does not represent any particular chemical process. To simplify the system and increase tractability, hydrogen and carbon monoxide feeds are considered in lieu of multi-step mechanisms for carbon dioxide conversion to methanol. General process descriptions for gas-phase synthesis, as well as thermophysical and reaction properties for carbon monoxide hydrogenation, were taken from the following publication:\n", - "\n", - "Nieminen, H.; Laari, A.; Koiranen, T. CO2 Hydrogenation to Methanol by a Liquid-Phase Process with Alcoholic Solvents: A Techno-Economic Analysis. Processes 2019, 7, 405. https://doi.org/10.3390/pr7070405" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. Introduction\n", - "\n", - "This example demonstrates a simulation of methanol synthesis from hydrogen and carbon monoxide. Each methanol flowsheet module includes several built-in methods. This notebook demonstrates building the flowsheet, implementing model scaling, initialization and solving a square problem, costing and final constrained optimization.\n", - "\n", - "The ```build_model()``` method creates the Pyomo concrete model and builds the flowsheet by importing thermophysical and reaction properties and unit models and defining stream connections between these units. This method also implements appropriate default scaling on state and property variables.\n", - "\n", - "The ```set_inputs()``` method adds the appropriate initial specifications on the feed streams and unit operations. Specifications upstream of the reactor largely remain fixed throughout the optimization.\n", - "\n", - "The ```scale_flowsheet()``` method implements generic variable, unit model state variable, unit model constraint and Arc equality constraint scaling via IDAES scaling tools. Scaling factors are hard-coded in the flowsheet scripts to adjust for order of magnitude factors in appropriate constraints and simplify numerical solver calculations.\n", - "\n", - "The ```initialize_flowsheet()``` method uses the initial guess to initialize the models sequentially, solving each unit and propagating the results to the outlet stream to converge the next unit more quickly. This occurs just before the flowsheet-level solver call.\n", - "\n", - "The ```add_costing()``` method creates new variables and constraints related to unit model capital cost and operating cost calculations, and defines an objective function for the process economics. This method is called after the flowsheet-level solver call, and the flowsheet is resolved once costing is added. Capital costs are estimated using built-in costing methods within IDAES, and operating costs are estimated from a combination of known cost coefficients and surrogate models.\n", - "\n", - "The ```report()``` method displays relevant model results after the flowsheet has been fully solved." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2. Problem Statement \n", - "\n", - "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", - "\n", - "## 2.1. Main Inputs: \n", - "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", - "- Pre-reactor compressor outlet pressure (Pa)\n", - "- Pre-reactor heater outlet temperature (K)\n", - "\n", - "## 2.2. Main Outputs:\n", - "- Extent of reaction (mol/s)\n", - "- Reactor duty (W)\n", - "- Turbine duty (W)\n", - "- Methanol recovery (%)\n", - "- Annual revenue (USD/year)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:16.638532300Z", - "start_time": "2026-02-20T21:01:16.620391500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:30.229848Z", - "iopub.status.busy": "2026-02-20T21:02:30.229848Z", - "iopub.status.idle": "2026-02-20T21:02:30.235273Z", - "shell.execute_reply": "2026-02-20T21:02:30.235273Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3. Import and Solve Flowsheet\n", - "## 3.1 Import Pyomo and IDAES Libraries" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, let's import the relevant Pyomo and IDAES Libraries:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:19.471901300Z", - "start_time": "2026-02-20T21:01:16.639577700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:30.264498Z", - "iopub.status.busy": "2026-02-20T21:02:30.264498Z", - "iopub.status.idle": "2026-02-20T21:02:32.853029Z", - "shell.execute_reply": "2026-02-20T21:02:32.853029Z" - } - }, - "outputs": [], - "source": [ - "import pytest\n", - "import os\n", - "\n", - "# Import Pyomo libraries\n", - "from pyomo.environ import (\n", - " Constraint,\n", - " Objective,\n", - " Var,\n", - " Expression,\n", - " Param,\n", - " ConcreteModel,\n", - " TransformationFactory,\n", - " value,\n", - " maximize,\n", - " units as pyunits,\n", - ")\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.network import Arc\n", - "\n", - "# Import IDAES core libraries\n", - "from idaes.core import FlowsheetBlock\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util import scaling as iscale\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "from idaes.core.util.initialization import propagate_state\n", - "\n", - "# Import required property modules\n", - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "\n", - "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", - "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", - "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", - "\n", - "from idaes.models.unit_models import (\n", - " Feed,\n", - " Mixer,\n", - " Heater,\n", - " Compressor,\n", - " Turbine,\n", - " StoichiometricReactor,\n", - " Flash,\n", - " Product,\n", - ")\n", - "from idaes.models.unit_models.mixer import MomentumMixingType\n", - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core import UnitModelCostingBlock\n", - "from idaes.models.costing.SSLW import SSLWCosting\n", - "\n", - "# import flowsheet functions\n", - "from methanol_flowsheet import (\n", - " build_model,\n", - " set_inputs,\n", - " scale_flowsheet,\n", - " initialize_flowsheet,\n", - " add_costing,\n", - " report,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.2 Build and Solve Flowsheet\n", - "The methanol flowsheet methods are called sequentially below, following the workflow contained in the ```main()``` method in `methanol_flowsheet.py`. First, let's set the solver options. IDAES contains a default solver `get_solver` which calls IPOPT using standard settings, and we set an iteration cap of 100 to catch nonconverging solver runs." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:19.487034800Z", - "start_time": "2026-02-20T21:01:19.478574800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:32.855088Z", - "iopub.status.busy": "2026-02-20T21:02:32.855088Z", - "iopub.status.idle": "2026-02-20T21:02:32.858220Z", - "shell.execute_reply": "2026-02-20T21:02:32.858220Z" - } - }, - "outputs": [], - "source": [ - "# Set solver options\n", - "solver = get_solver() # IPOPT\n", - "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", - "solver.options = optarg" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will build and solve the initial flowsheet using imported flowsheet methods - see `methanol_flowsheet.py` for complete method scripts.\n", - "\n", - "In the code below, we first define a Pyomo model object and build the model by defining each unit block with relevant property packages. As mentioned earlier, only the Flash unit (and the liquid outlet Product block) employ the VLE property package to ensure fast convergence of vapor-only processes.\n", - "\n", - "The process inputs are set for stoichiometric hydrogen and carbon monoxide feeds according to the process diagram in section 2.2. In the output below, the script returns the expected degrees of freedom for the model for each unit (compressor pressure change, heater duty, reactor duty and conversion, turbine pressure change and efficiency, cooler duty and flash duty and pressure change) and the actual model degrees of freedom before input specification, after the feed inputs are specified (flow, enthalpy, pressure, and composition for each feed) and after the unit model inputs are specified.\n", - "\n", - "After setting process inputs, we have a square problem for initialization. Here, we first implement IDAES scaling tools to create a more tractable problem during the solve step, and then sequentially initialize and propagate results from each unit block. As expected, the model only performs dew and bubble point calculations for the Flash and CH3OH product blocks where liquid phases are present and we obtain a square, solved problem:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:21.865944300Z", - "start_time": "2026-02-20T21:01:19.489272100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:32.860304Z", - "iopub.status.busy": "2026-02-20T21:02:32.859268Z", - "iopub.status.idle": "2026-02-20T21:02:35.178680Z", - "shell.execute_reply": "2026-02-20T21:02:35.178680Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unit degrees of freedom\n", - "M101 0\n", - "C101 1\n", - "H101 1\n", - "R101 2\n", - "T101 2\n", - "H102 1\n", - "F101 2\n", - "Total DOF: 23\n", - "DOF after streams specified: 9\n", - "DOF after units specified: 0\n", - "\n", - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H2.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H2: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.CO.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.CO: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:33 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:34 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2026-02-20 14:02:35 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF before solve: 0\n", - "\n", - "Solving initial problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 955\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 607\n", - "\n", - "Total number of variables............................: 310\n", - " variables with only lower bounds: 35\n", - " variables with lower and upper bounds: 258\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 310\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 2.79e+02 2.77e+00 -1.0 1.00e-02 - 9.90e-01 9.90e-01h 1\n", - " 2 0.0000000e+00 2.77e+00 1.21e+00 -1.0 1.00e-04 - 9.90e-01 9.90e-01h 1\n", - " 3 0.0000000e+00 6.98e-10 1.00e+03 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 3\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Constraint violation....: 1.1368683772161603e-13 6.9849193096160889e-10\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 1.1368683772161603e-13 6.9849193096160889e-10\n", - "\n", - "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.003\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - } - ], - "source": [ - "# Build and solve flowsheet\n", - "m = ConcreteModel()\n", - "build_model(m) # build flowsheet by adding unit models and property packages\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "\n", - "results = solver.solve(m, tee=True) # initial square problem solve" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.3 Flowsheet Costing and Optimization\n", - "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs. Additional, we calculate reactor operating costs as a function of conversion and assume constant rates for electricity, heating and cooling costs. Capital costs are annualized over 15 years, and revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, including a check on the reaction stoichiometry, relevant duty and state variable values, economic results, and stream tables for feed and product streams:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:22.045476800Z", - "start_time": "2026-02-20T21:01:21.869055Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:35.179690Z", - "iopub.status.busy": "2026-02-20T21:02:35.179690Z", - "iopub.status.idle": "2026-02-20T21:02:35.297484Z", - "shell.execute_reply": "2026-02-20T21:02:35.297484Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving with costing...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 971\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 611\n", - "\n", - "Total number of variables............................: 319\n", - " variables with only lower bounds: 43\n", - " variables with lower and upper bounds: 258\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 319\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8492051e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.9068962e+07 5.76e+04 6.45e+01 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", - " 2 -2.9074767e+07 5.71e+02 9.98e+00 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", - " 3 -2.9074825e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9074825e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 4\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -4.4948186430824137e+01 -2.9074824816033222e+07\n", - "Dual infeasibility......: 3.6708958239217049e-07 2.3745263485255724e-01\n", - "Constraint violation....: 4.5474735088646412e-12 1.0477378964424133e-09\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 2.3745263485255724e-01\n", - "\n", - "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.003\n", - "Total CPU secs in NLP function evaluations = 0.001\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initial solution process results:" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\n", - "Extent of reaction: 237.6004779\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.21917830318435\n", - "Duty from Reaction (MW)): 21.536107316856\n", - "Turbine work (MW): -0.9593346445867499\n", - "Mixer outlet temperature (C)): 20.051714213753257\n", - "Compressor outlet temperature (C)): 20.051714213753257\n", - "Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.8781524424324\n", - "Turbine outlet pressure (Pa)): 3100000.0\n", - "Cooler outlet temperature (C)): 134.0\n", - "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 60.004430129216836\n", - "annualized capital cost ($/year) = 219790.5044704343\n", - "operating cost ($/year) = 380701687.4964806\n", - "sales ($/year) = 64685201172.198135\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29074824.816033214\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 336.23\n", - " Total Mole Fraction CH4 dimensionless 2.8373e-06\n", - " Total Mole Fraction CO dimensionless 0.23555\n", - " Total Mole Fraction H2 dimensionless 0.48181\n", - " Total Mole Fraction CH3OH dimensionless 0.28263\n", - " Molar Enthalpy joule / mole -80218.\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 142.57\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3813e+05\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "print(\"Solving with costing...\")\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:22.214714100Z", - "start_time": "2026-02-20T21:01:22.048059700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:35.299499Z", - "iopub.status.busy": "2026-02-20T21:02:35.298494Z", - "iopub.status.idle": "2026-02-20T21:02:35.406313Z", - "shell.execute_reply": "2026-02-20T21:02:35.406313Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Solving optimization problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 975\n", - "Number of nonzeros in inequality constraint Jacobian.: 8\n", - "Number of nonzeros in Lagrangian Hessian.............: 613\n", - "\n", - "Total number of variables............................: 322\n", - " variables with only lower bounds: 43\n", - " variables with lower and upper bounds: 259\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 318\n", - "Total number of inequality constraints...............: 8\n", - " inequality constraints with only lower bounds: 4\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 4\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8492012e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.8402807e+07 2.72e+04 9.71e+01 -1.0 8.82e+06 - 4.99e-02 2.59e-02h 1\n", - " 2 -2.8406592e+07 2.70e+04 9.55e+01 -1.0 8.56e+06 - 7.51e-02 8.58e-03h 1\n", - " 3 -2.8493711e+07 2.29e+04 3.69e+02 -1.0 8.41e+06 - 1.67e-01 1.52e-01h 1\n", - " 4 -2.8493256e+07 2.28e+04 1.20e+04 -1.0 4.60e+06 - 1.00e-01 2.61e-03h 1\n", - " 5 -2.8504483e+07 2.24e+04 1.20e+04 -1.0 4.52e+06 - 2.44e-02 2.38e-02h 1\n", - " 6 -2.8536508e+07 2.16e+04 2.28e+04 -1.0 4.39e+06 - 5.48e-02 6.86e-02h 1\n", - " 7 -2.8537589e+07 2.16e+04 1.35e+05 -1.0 3.94e+06 - 2.56e-01 2.49e-03h 1\n", - " 8 -2.8537637e+07 2.15e+04 6.77e+06 -1.0 1.30e+06 - 4.68e-01 1.17e-04h 1\n", - " 9 -2.8910081e+07 8.51e+04 2.07e+06 -1.0 1.31e+06 - 4.38e-01 9.05e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -2.8916017e+07 7.81e+04 1.11e+08 -1.0 9.39e+04 -4.0 3.56e-03 8.26e-02h 1\n", - " 11 -2.8916050e+07 7.80e+04 1.11e+08 -1.0 8.73e+04 -4.5 9.12e-02 9.05e-04h 1\n", - " 12 -2.8951501e+07 1.29e+04 3.00e+07 -1.0 8.73e+04 - 1.37e-02 9.90e-01h 1\n", - " 13 -2.8964697e+07 3.52e+03 9.82e+06 -1.0 2.95e+04 - 8.80e-01 9.92e-01h 1\n", - " 14 -2.9150638e+07 4.25e+00 6.53e+07 -1.0 1.59e+04 - 9.88e-01 1.00e+00h 1\n", - " 15 -3.2694771e+07 3.47e+03 1.38e+08 -1.0 3.00e+05 - 3.58e-01 1.00e+00f 1\n", - " 16 -3.9657884e+07 3.74e+02 4.98e+06 -1.0 6.48e+05 - 9.11e-01 1.00e+00F 1\n", - " 17 -5.8700677e+07 2.03e+04 1.12e+06 -1.0 2.00e+06 - 2.65e-01 1.00e+00F 1\n", - " 18 -7.8085174e+07 1.40e+05 4.14e+05 -1.0 4.34e+06 - 7.55e-01 7.57e-01f 1\n", - " 19 -7.9333792e+07 1.60e+05 2.63e+05 -1.0 3.52e+06 - 9.63e-01 3.03e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -7.7164009e+07 3.20e+03 7.59e+03 -1.0 4.56e+05 - 9.91e-01 1.00e+00h 1\n", - " 21 -7.7545831e+07 3.83e+03 5.53e+01 -1.0 2.78e+05 - 1.00e+00 1.00e+00h 1\n", - " 22 -7.7683360e+07 9.76e+02 2.23e+06 -2.5 6.32e+04 - 1.00e+00 7.70e-01h 1\n", - " 23 -7.7696221e+07 8.35e+00 1.48e+02 -2.5 6.87e+04 - 1.00e+00 1.00e+00h 1\n", - " 24 -7.7696183e+07 8.31e-03 4.61e-03 -2.5 2.13e+03 - 1.00e+00 1.00e+00h 1\n", - " 25 -7.7699949e+07 5.36e+00 1.27e+04 -5.7 7.60e+04 - 9.49e-01 9.94e-01f 1\n", - " 26 -7.7700458e+07 8.84e+01 1.03e+03 -5.7 3.66e+05 - 9.25e-01 9.72e-01h 1\n", - " 27 -7.7700530e+07 1.74e+01 1.01e+01 -5.7 6.59e+04 - 1.00e+00 8.03e-01h 1\n", - " 28 -7.7700531e+07 2.07e-04 4.22e-06 -5.7 1.25e+03 - 1.00e+00 1.00e+00h 1\n", - " 29 -7.7700536e+07 9.48e-04 1.29e-01 -8.6 1.69e+03 - 1.00e+00 9.99e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.7700536e+07 6.52e-09 5.32e-11 -8.6 1.52e+00 - 1.00e+00 1.00e+00f 1\n", - " 31 -7.7700536e+07 8.38e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 31\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -1.2012103932708916e+02 -7.7700535938862860e+07\n", - "Dual infeasibility......: 6.9713197782916848e-11 4.5094122229452131e-05\n", - "Constraint violation....: 9.4587448984384537e-11 8.3819031715393066e-09\n", - "Complementarity.........: 1.4074777632989367e-11 9.1042982264387185e-06\n", - "Overall NLP error.......: 9.4587448984384537e-11 4.5094122229452131e-05\n", - "\n", - "\n", - "Number of objective function evaluations = 34\n", - "Number of objective gradient evaluations = 32\n", - "Number of equality constraint evaluations = 34\n", - "Number of inequality constraint evaluations = 34\n", - "Number of equality constraint Jacobian evaluations = 32\n", - "Number of inequality constraint Jacobian evaluations = 32\n", - "Number of Lagrangian Hessian evaluations = 31\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.027\n", - "Total CPU secs in NLP function evaluations = 0.001\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal solution process results:" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "Extent of reaction: 269.2805447879921\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.8500000099999546\n", - "Reactor duty (MW): -51.363573577545786\n", - "Duty from Reaction (MW)): 24.407588579583603\n", - "Turbine work (MW): -1.9904899177794815\n", - "Mixer outlet temperature (C)): 20.0517142137536\n", - "Compressor outlet temperature (C)): 20.0517142137536\n", - "Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 231.85000468716584\n", - "Turbine outlet temperature (C)): 139.85888172675686\n", - "Turbine outlet pressure (Pa)): 1427653.3547820917\n", - "Cooler outlet temperature (C)): 52.56999709299214\n", - "Flash outlet temperature (C)): 134.0\n", - "Methanol recovery(%): 92.8035547465754\n", - "annualized capital cost ($/year) = 235547.18924473316\n", - "operating cost ($/year) = 451663512.6847629\n", - "sales ($/year) = 113381889876.90082\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 77700535.93886285\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 165.54\n", - " Total Mole Fraction CH4 dimensionless 5.7630e-06\n", - " Total Mole Fraction CO dimensionless 0.28706\n", - " Total Mole Fraction H2 dimensionless 0.59587\n", - " Total Mole Fraction CH3OH dimensionless 0.11706\n", - " Molar Enthalpy joule / mole -52313.\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 249.90\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3792e+05\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "opt_res = solver.solve(m, tee=True)\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, the process achieves a much greater revenue as a result of increasing conversion and lowering the inlet temperature to the Flash unit to encourage methanol recovery in the liquid phase. The results show a slight increase in equipment and operating costs from these changes, as well as a small loss of methanol in the exhaust." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 4. Problem Statement - Analyzing Benefit of Recycling Flash Vapor\n", - "\n", - "To increase the efficiency of the process as well as overall methanol production and revenue, we can add a recycle stream to send most of the Flash vapor back to the start of the process. This will reduce methanol loss in the exhaust and increase feed utilization, resulting in increased operating costs and increased production (revenue) at the same conversion. Note that for conversions less than 100%, a simulation with no purge will never converge due to accumulation of gases within the system. Therefore, to ensure we close the mass balance we set a lower bound at 10% purge from the Flash vapor to the exhaust. We expect to see a marginal increase in operating costs due to increased flow, and a much larger increase in overall production resulting in a higher total revenue.\n", - "\n", - "By adding a recycle to the flowsheet, we significantly decrease the tractability of the problem and require a better initial guess. The SequentialDecomposition algorithm automatically determines a stream to *tear*, or use to break the solve loop, and iterates from a set of user-supplied initial guesses until converging on the optimal solution. The code below calls an initialization method to automatically determine the tear stream. See the initialization method of `methanol_flowsheet_w_recycle.py` for further details Sequential Decomposition scheme.\n", - "\n", - "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", - "\n", - "## 4.1. Main Inputs: \n", - "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", - "- Pre-reactor compressor outlet pressure (Pa)\n", - "- Pre-reactor heater outlet temperature (K)\n", - "\n", - "## 4.2. Main Outputs:\n", - "- Extent of reaction (mol/s)\n", - "- Reactor duty (W)\n", - "- Compressor duty (W)\n", - "- Turbine duty (W)\n", - "- Methanol recovery (%)\n", - "- Purge percentage (%)\n", - "- Annual revenue (USD/year)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:22.259161200Z", - "start_time": "2026-02-20T21:01:22.214714100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:35.408476Z", - "iopub.status.busy": "2026-02-20T21:02:35.408476Z", - "iopub.status.idle": "2026-02-20T21:02:35.414016Z", - "shell.execute_reply": "2026-02-20T21:02:35.414016Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(\"methanol_flowsheet_recycle.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 5. Import and Solve Recycle Flowsheet\n", - "## 5.1 Import Pyomo and IDAES Libraries\n", - "As we are rebuilding the model, we need to import require Pyomo and IDAES libraries:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:22.273109Z", - "start_time": "2026-02-20T21:01:22.260217300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:35.416309Z", - "iopub.status.busy": "2026-02-20T21:02:35.416309Z", - "iopub.status.idle": "2026-02-20T21:02:35.423025Z", - "shell.execute_reply": "2026-02-20T21:02:35.423025Z" - } - }, - "outputs": [], - "source": [ - "import pytest\n", - "import os\n", - "\n", - "# Import Pyomo libraries\n", - "from pyomo.environ import (\n", - " Constraint,\n", - " Objective,\n", - " Var,\n", - " Expression,\n", - " Param,\n", - " ConcreteModel,\n", - " TransformationFactory,\n", - " value,\n", - " maximize,\n", - " units as pyunits,\n", - ")\n", - "from pyomo.environ import TerminationCondition\n", - "from pyomo.network import Arc, SequentialDecomposition\n", - "\n", - "# Import IDAES core libraries\n", - "from idaes.core import FlowsheetBlock\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util import scaling as iscale\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "from idaes.core.util.initialization import propagate_state\n", - "\n", - "# Import required models\n", - "\n", - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "\n", - "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", - "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", - "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", - "\n", - "from idaes.models.unit_models import (\n", - " Feed,\n", - " Mixer,\n", - " Heater,\n", - " Compressor,\n", - " Turbine,\n", - " StoichiometricReactor,\n", - " Flash,\n", - " Separator as Splitter,\n", - " Product,\n", - ")\n", - "from idaes.models.unit_models.mixer import MomentumMixingType\n", - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core import UnitModelCostingBlock\n", - "from idaes.models.costing.SSLW import SSLWCosting\n", - "import idaes.logger as idaeslog\n", - "\n", - "# import flowsheet functions\n", - "from methanol_flowsheet_w_recycle import (\n", - " build_model,\n", - " set_inputs,\n", - " scale_flowsheet,\n", - " initialize_flowsheet,\n", - " add_costing,\n", - " report,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.2 Build and Solve Recycle Flowsheet\n", - "As before, we will first build the flowsheet, set required inputs, initialize and solve a square problem. Recycling methanol to pre-reactor blocks complicates VLE calculations, and limiting VLE calculations to the Flash unit and liquid Product block greatly increases tractability during initialization. All initial feed and unit specifications are identical to the non-recycle case; the Sequential Decomposition algorithm automatically selects the compressor feed as the tear stream and uses \"no recycle\" results as a first guess. In the output below, the solver solves all units and then resolves select blocks with updated inlet results, followed by a full flowsheet solve:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:25.017570500Z", - "start_time": "2026-02-20T21:01:22.274110600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:35.425050Z", - "iopub.status.busy": "2026-02-20T21:02:35.424039Z", - "iopub.status.idle": "2026-02-20T21:02:37.938812Z", - "shell.execute_reply": "2026-02-20T21:02:37.938812Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unit degrees of freedom\n", - "M101 0\n", - "C101 1\n", - "H101 1\n", - "R101 2\n", - "T101 2\n", - "H102 1\n", - "F101 2\n", - "M102 0\n", - "S101 1\n", - "Total DOF: 24\n", - "DOF after streams specified: 10\n", - "DOF after units specified: 0\n", - "\n", - "Tear Stream:\n", - "fs.s02 : fs.M102.outlet to fs.C101.inlet\n", - "\n", - "Calculation order:\n", - "fs.H2\n", - "fs.M101\n", - "fs.R101\n", - "fs.T101\n", - "fs.H102\n", - "fs.F101\n", - "fs.S101\n", - "fs.EXHAUST\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initial DOF = 0\n", - "Solving fs.H2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.CO\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.C101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.M101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.H101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.R101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.T101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.H102\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.F101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.S101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.CH3OH\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.EXHAUST\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.M102\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.H2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.CO\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.M101\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = 0\n", - "Solving fs.EXHAUST\n" - ] + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:04.629603300Z", + "start_time": "2026-02-20T21:01:04.619279Z" + }, + "tags": [ + "header", + "hide-cell" + ] + }, + "outputs": [], + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Methanol Synthesis Flowsheet Example\n", + "Maintainer: Brandon Paul \n", + "Author: Brandon Paul \n", + "Updated: 2023-06-01 \n", + "\n", + "The purpose of this notebook is to demonstrate flowsheet synthesis integrating IDAES modeling tools, including the Unit Model Library, Property and Reaction Framework, IDAES scaling tools and the Process Costing Framework. The example leverages imports from external flowsheet scripts, and demonstrates implementation of separate VLE and vapor-only property packages to reduce model complexity where applicable.\n", + "\n", + "## Simplified Hydrogen Reformation System\n", + "\n", + "This example demonstrates a steady-state model of methanol synthesis from hydrogen and carbon monoxide. To simulate relevant natural gas components, the reactant vapors are mixed stoichiometrically and brought to optimal reaction conditions prior to entering the gas-phase reactor. Vapor liquid equilibrium is mainly applicable in the post-reactor Flash unit for methanol recovery, and is accounted for by separate vapor and VLE thermophysical property packages. See `methanol_flowsheet.py` for more information on how to assemble the flowsheet, as well as [idaes_examples.mod.methanol.methanol_ideal_VLE.py](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_VLE.py), [idaes_examples.mod.methanol.methanol_ideal_vapor](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_ideal_vapor.py) and [idaes_examples.mod.methanol.methanol_reactions](https://github.com/IDAES/examples-pse/tree/main/pkg/idaes_examples/common/methanol/methanol_reactions.py) for more information on the thermophyscial and reaction properties.\n", + "\n", + "This example is a reasonable approximation for gas-phase methanol synthesis systems and does not represent any particular chemical process. To simplify the system and increase tractability, hydrogen and carbon monoxide feeds are considered in lieu of multi-step mechanisms for carbon dioxide conversion to methanol. General process descriptions for gas-phase synthesis, as well as thermophysical and reaction properties for carbon monoxide hydrogenation, were taken from the following publication:\n", + "\n", + "Nieminen, H.; Laari, A.; Koiranen, T. CO2 Hydrogenation to Methanol by a Liquid-Phase Process with Alcoholic Solvents: A Techno-Economic Analysis. Processes 2019, 7, 405. https://doi.org/10.3390/pr7070405" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Introduction\n", + "\n", + "This example demonstrates a simulation of methanol synthesis from hydrogen and carbon monoxide. Each methanol flowsheet module includes several built-in methods. This notebook demonstrates building the flowsheet, implementing model scaling, initialization and solving a square problem, costing and final constrained optimization.\n", + "\n", + "The ```build_model()``` method creates the Pyomo concrete model and builds the flowsheet by importing thermophysical and reaction properties and unit models and defining stream connections between these units. This method also implements appropriate default scaling on state and property variables.\n", + "\n", + "The ```set_inputs()``` method adds the appropriate initial specifications on the feed streams and unit operations. Specifications upstream of the reactor largely remain fixed throughout the optimization.\n", + "\n", + "The ```scale_flowsheet()``` method implements generic variable, unit model state variable, unit model constraint and Arc equality constraint scaling via IDAES scaling tools. Scaling factors are hard-coded in the flowsheet scripts to adjust for order of magnitude factors in appropriate constraints and simplify numerical solver calculations.\n", + "\n", + "The ```initialize_flowsheet()``` method uses the initial guess to initialize the models sequentially, solving each unit and propagating the results to the outlet stream to converge the next unit more quickly. This occurs just before the flowsheet-level solver call.\n", + "\n", + "The ```add_costing()``` method creates new variables and constraints related to unit model capital cost and operating cost calculations, and defines an objective function for the process economics. This method is called after the flowsheet-level solver call, and the flowsheet is resolved once costing is added. Capital costs are estimated using built-in costing methods within IDAES, and operating costs are estimated from a combination of known cost coefficients and surrogate models.\n", + "\n", + "The ```report()``` method displays relevant model results after the flowsheet has been fully solved." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2. Problem Statement \n", + "\n", + "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", + "\n", + "## 2.1. Main Inputs: \n", + "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", + "- Pre-reactor compressor outlet pressure (Pa)\n", + "- Pre-reactor heater outlet temperature (K)\n", + "\n", + "## 2.2. Main Outputs:\n", + "- Extent of reaction (mol/s)\n", + "- Reactor duty (W)\n", + "- Turbine duty (W)\n", + "- Methanol recovery (%)\n", + "- Annual revenue (USD/year)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n", - "Solving fs.CH3OH\n" - ] + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:04.649464300Z", + "start_time": "2026-02-20T21:01:04.632133500Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet.png\")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 3. Import and Solve Flowsheet\n", + "## 3.1 Import Pyomo and IDAES Libraries" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's import the relevant Pyomo and IDAES Libraries:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:07.389407500Z", + "start_time": "2026-02-20T21:01:04.652988700Z" + } + }, + "outputs": [], + "source": [ + "import pytest\n", + "import os\n", + "\n", + "# Import Pyomo libraries\n", + "from pyomo.environ import (\n", + " Constraint,\n", + " Objective,\n", + " Var,\n", + " Expression,\n", + " Param,\n", + " ConcreteModel,\n", + " TransformationFactory,\n", + " value,\n", + " maximize,\n", + " units as pyunits,\n", + ")\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.network import Arc\n", + "\n", + "# Import IDAES core libraries\n", + "from idaes.core import FlowsheetBlock\n", + "from idaes.core.solvers import get_solver\n", + "from idaes.core.util import scaling as iscale\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "from idaes.core.util.initialization import propagate_state\n", + "\n", + "# Import required property modules\n", + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "\n", + "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", + "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", + "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", + "\n", + "from idaes.models.unit_models import (\n", + " Feed,\n", + " Mixer,\n", + " Heater,\n", + " Compressor,\n", + " Turbine,\n", + " StoichiometricReactor,\n", + " Flash,\n", + " Product,\n", + ")\n", + "from idaes.models.unit_models.mixer import MomentumMixingType\n", + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core import UnitModelCostingBlock\n", + "from idaes.models.costing.SSLW import SSLWCosting\n", + "\n", + "# import flowsheet functions\n", + "from methanol_flowsheet import (\n", + " build_model,\n", + " set_inputs,\n", + " scale_flowsheet,\n", + " initialize_flowsheet,\n", + " add_costing,\n", + " report,\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3.2 Build and Solve Flowsheet\n", + "The methanol flowsheet methods are called sequentially below, following the workflow contained in the ```main()``` method in `methanol_flowsheet.py`. First, let's set the solver options. IDAES contains a default solver `get_solver` which calls IPOPT using standard settings, and we set an iteration cap of 100 to catch nonconverging solver runs." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:07.399593900Z", + "start_time": "2026-02-20T21:01:07.390910200Z" + } + }, + "outputs": [], + "source": [ + "# Set solver options\n", + "solver = get_solver() # IPOPT\n", + "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", + "solver.options = optarg" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will build and solve the initial flowsheet using imported flowsheet methods - see `methanol_flowsheet.py` for complete method scripts.\n", + "\n", + "In the code below, we first define a Pyomo model object and build the model by defining each unit block with relevant property packages. As mentioned earlier, only the Flash unit (and the liquid outlet Product block) employ the VLE property package to ensure fast convergence of vapor-only processes.\n", + "\n", + "The process inputs are set for stoichiometric hydrogen and carbon monoxide feeds according to the process diagram in section 2.2. In the output below, the script returns the expected degrees of freedom for the model for each unit (compressor pressure change, heater duty, reactor duty and conversion, turbine pressure change and efficiency, cooler duty and flash duty and pressure change) and the actual model degrees of freedom before input specification, after the feed inputs are specified (flow, enthalpy, pressure, and composition for each feed) and after the unit model inputs are specified.\n", + "\n", + "After setting process inputs, we have a square problem for initialization. Here, we first implement IDAES scaling tools to create a more tractable problem during the solve step, and then sequentially initialize and propagate results from each unit block. As expected, the model only performs dew and bubble point calculations for the Flash and CH3OH product blocks where liquid phases are present and we obtain a square, solved problem:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "DOF = " - ] + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.234663Z", + "start_time": "2026-02-20T21:01:07.401096600Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unit degrees of freedom\n", + "M101 0\n", + "C101 1\n", + "H101 1\n", + "R101 2\n", + "T101 2\n", + "H102 1\n", + "F101 2\n", + "Total DOF: 23\n", + "DOF after streams specified: 9\n", + "DOF after units specified: 0\n", + "\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.H2: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.CO: Initialization Complete.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.H2_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.CO_WGS_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101.mixed_state: Property package initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:46 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.C101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.H101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume.reactions: Initialization Complete.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.R101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.control_volume.properties_out: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:47 [INFO] idaes.init.fs.T101.properties_isentropic: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101.properties_isentropic: Property package initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.T101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.H102: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:48 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101.control_volume: Initialization Complete\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.F101: Initialization Complete: optimal - Optimal Solution Found\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.EXHAUST: Initialization Complete.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Starting initialization\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Bubble, dew, and critical point initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Equilibrium temperature initialization completed.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Phase equilibrium initialization: optimal - Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH.properties: Property package initialization: optimal - Optimal Solution Found.\n", + "2026-07-22 11:42:49 [INFO] idaes.init.fs.CH3OH: Initialization Complete.\n", + "DOF before solve: 0\n", + "\n", + "Solving initial problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 955\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 607\n", + "\n", + "Total number of variables............................: 310\n", + " variables with only lower bounds: 35\n", + " variables with lower and upper bounds: 258\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 310\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 2.79e+02 2.77e+00 -1.0 1.00e-02 - 9.90e-01 9.90e-01h 1\n", + " 2 0.0000000e+00 2.77e+00 1.21e+00 -1.0 1.00e-04 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 9.31e-10 0.00e+00 -1.0 9.90e-07 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 1.1368683772161603e-13 9.3132257461547852e-10\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 1.1368683772161603e-13 9.3132257461547852e-10\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total seconds in IPOPT = 0.003\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Build and solve flowsheet\n", + "m = ConcreteModel()\n", + "build_model(m) # build flowsheet by adding unit models and property packages\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "\n", + "results = solver.solve(m, tee=True) # initial square problem solve" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3.3 Flowsheet Costing and Optimization\n", + "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs. Additional, we calculate reactor operating costs as a function of conversion and assume constant rates for electricity, heating and cooling costs. Capital costs are annualized over 15 years, and revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, including a check on the reaction stoichiometry, relevant duty and state variable values, economic results, and stream tables for feed and product streams:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Final DOF = 0\n", - "DOF before solve: 0\n", - "\n", - "Solving initial problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.373826200Z", + "start_time": "2026-02-20T21:01:09.242152800Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving with costing...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 971\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 611\n", + "\n", + "Total number of variables............................: 319\n", + " variables with only lower bounds: 43\n", + " variables with lower and upper bounds: 258\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 319\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8492051e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.9068962e+07 5.76e+04 6.45e+01 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", + " 2 -2.9074767e+07 5.71e+02 9.98e+00 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", + " 3 -2.9074825e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9074825e+07 1.63e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9074825e+07 1.16e-09 9.87e-08 -1.0 2.66e-08 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 5\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -4.4948186430824109e+01 -2.9074824816033181e+07\n", + "Dual infeasibility......: 9.8709848486689587e-08 6.3850664070387003e-02\n", + "Constraint violation....: 4.5474735088646412e-12 1.1641532182693481e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.8709848486689587e-08 6.3850664070387003e-02\n", + "\n", + "\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 6\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Initial solution process results:\n", + "\n", + "\n", + "Extent of reaction: 237.60047790000004\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.75\n", + "Reactor duty (MW): -45.21917830318437\n", + "Duty from Reaction (MW)): 21.536107316856004\n", + "Turbine work (MW): -0.9593346445867349\n", + "Mixer outlet temperature (C)): 20.0517142137536\n", + "Compressor outlet temperature (C)): 20.05171421375354\n", + "Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 234.0\n", + "Turbine outlet temperature (C)): 192.87815244243325\n", + "Turbine outlet pressure (Pa)): 3100000.0\n", + "Cooler outlet temperature (C)): 134.0\n", + "Flash outlet temperature (C)): 134.0\n", + "Methanol recovery(%): 60.00443012921678\n", + "annualized capital cost ($/year) = 219790.50447043462\n", + "operating cost ($/year) = 380701687.4964803\n", + "sales ($/year) = 64685201172.198105\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 29074824.816033185\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 336.23\n", + " Total Mole Fraction CH4 dimensionless 2.8373e-06\n", + " Total Mole Fraction CO dimensionless 0.23555\n", + " Total Mole Fraction H2 dimensionless 0.48181\n", + " Total Mole Fraction CH3OH dimensionless 0.28263\n", + " Molar Enthalpy joule / mole -80218.\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 142.57\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3813e+05\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "print(\"Solving with costing...\")\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1211\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 768\n", - "\n", - "Total number of variables............................: 397\n", - " variables with only lower bounds: 41\n", - " variables with lower and upper bounds: 336\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 397\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 2.79e+02 4.22e+03 -1.0 1.96e+03 - 9.90e-01 9.90e-01h 1\n", - " 2 0.0000000e+00 2.77e+00 3.86e+03 -1.0 2.03e+01 - 9.90e-01 9.90e-01h 1\n", - " 3 0.0000000e+00 7.44e-06 1.01e+03 -1.0 2.01e-01 - 9.90e-01 1.00e+00h 1\n", - "Cannot recompute multipliers for feasibility problem. Error in eq_mult_calculator\n", - "\n", - "Number of Iterations....: 3\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 1.0099088928127792e+05 1.0099088928127792e+05\n", - "Constraint violation....: 2.4014227693119351e-10 7.4444105848670006e-06\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 2.4014227693119351e-10 1.0099088928127792e+05\n", - "\n", - "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.006\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] - } - ], - "source": [ - "# Build and solve flowsheet\n", - "solver = get_solver() # IPOPT\n", - "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", - "solver.options = optarg\n", - "\n", - "m = ConcreteModel() # create a new model so we may reference 'm' below\n", - "build_model(m) # build flowsheet\n", - "set_inputs(m) # unit and stream specifications\n", - "scale_flowsheet(m) # flowsheet and unit model level scaling\n", - "\n", - "# let the solver determine the tear stream\n", - "initialize_flowsheet(m) # rigorous initialization scheme\n", - "\n", - "print(\"DOF before solve: \", degrees_of_freedom(m))\n", - "print()\n", - "print(\"Solving initial problem...\")\n", - "results = solver.solve(m, tee=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.3 Flowsheet Costing and Optimization\n", - "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs, reactor operating costs and utility costs for heating, cooling and electricity. As before, revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, which are updated for new results with the presence of a recycle stream:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:25.159753600Z", - "start_time": "2026-02-20T21:01:25.017570500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:37.940822Z", - "iopub.status.busy": "2026-02-20T21:02:37.940822Z", - "iopub.status.idle": "2026-02-20T21:02:38.068616Z", - "shell.execute_reply": "2026-02-20T21:02:38.068616Z" + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.500156800Z", + "start_time": "2026-02-20T21:01:09.382424800Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving optimization problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 160 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 975\n", + "Number of nonzeros in inequality constraint Jacobian.: 8\n", + "Number of nonzeros in Lagrangian Hessian.............: 613\n", + "\n", + "Total number of variables............................: 322\n", + " variables with only lower bounds: 43\n", + " variables with lower and upper bounds: 259\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 318\n", + "Total number of inequality constraints...............: 8\n", + " inequality constraints with only lower bounds: 4\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 4\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8492012e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.8402807e+07 2.72e+04 9.71e+01 -1.0 8.82e+06 - 4.99e-02 2.59e-02h 1\n", + " 2 -2.8406592e+07 2.70e+04 9.55e+01 -1.0 8.56e+06 - 7.51e-02 8.58e-03h 1\n", + " 3 -2.8493711e+07 2.29e+04 3.69e+02 -1.0 8.41e+06 - 1.67e-01 1.52e-01h 1\n", + " 4 -2.8493256e+07 2.28e+04 1.20e+04 -1.0 4.60e+06 - 1.00e-01 2.61e-03h 1\n", + " 5 -2.8504483e+07 2.24e+04 1.20e+04 -1.0 4.52e+06 - 2.44e-02 2.38e-02h 1\n", + " 6 -2.8536508e+07 2.16e+04 2.28e+04 -1.0 4.39e+06 - 5.48e-02 6.86e-02h 1\n", + " 7 -2.8537589e+07 2.16e+04 1.35e+05 -1.0 3.94e+06 - 2.56e-01 2.49e-03h 1\n", + " 8 -2.8537637e+07 2.15e+04 6.77e+06 -1.0 1.30e+06 - 4.68e-01 1.17e-04h 1\n", + " 9 -2.8910081e+07 8.51e+04 2.07e+06 -1.0 1.31e+06 - 4.38e-01 9.05e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -2.8914165e+07 7.59e+04 7.45e+06 -1.0 9.51e+04 - 9.00e-01 1.08e-01h 1\n", + " 11 -2.8947367e+07 1.17e+03 1.82e+05 -1.0 8.76e+04 - 9.09e-01 9.90e-01h 1\n", + " 12 -2.8953051e+07 1.08e+01 5.44e+06 -1.0 1.43e+03 -4.0 3.59e-02 9.92e-01h 1\n", + " 13 -2.8953104e+07 4.13e-04 1.09e+05 -1.0 2.11e+01 -4.5 9.90e-01 1.00e+00h 1\n", + " 14 -2.8953015e+07 2.97e-05 8.41e+04 -1.0 3.36e+01 -5.0 9.90e-01 1.00e+00f 1\n", + " 15 -2.8952945e+07 9.83e-05 7.75e+02 -1.0 6.25e+01 -5.4 9.91e-01 1.00e+00f 1\n", + " 16 -2.8952999e+07 1.24e-05 4.07e+00 -1.7 2.92e+01 -5.9 1.00e+00 1.00e+00f 1\n", + " 17 -2.8953295e+07 1.59e-05 3.08e+04 -3.8 1.68e+01 -6.4 9.84e-01 1.00e+00f 1\n", + " 18 -6.7235329e+07 3.98e+05 3.08e+04 -3.8 3.24e+06 - 6.31e-04 1.00e+00f 1\n", + " 19 -6.7161096e+07 3.96e+05 3.08e+04 -3.8 3.97e+05 -6.9 4.51e-04 6.00e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r-6.7161096e+07 3.96e+05 1.00e+03 1.1 0.00e+00 -7.3 0.00e+00 3.70e-07R 5\n", + " 21r-6.0126088e+07 1.13e+05 9.98e+02 1.1 9.47e+08 - 7.54e-04 8.89e-04f 1\n", + " 22 -5.8571015e+07 9.76e+04 1.26e+02 -3.8 1.33e+06 - 2.10e-01 1.37e-01h 1\n", + " 23 -5.8570701e+07 9.76e+04 4.63e+04 -3.8 1.17e+06 - 5.53e-01 3.23e-05h 1\n", + " 24 -5.8606170e+07 8.79e+04 1.84e+05 -3.8 2.62e+06 - 5.56e-03 9.99e-02h 1\n", + " 25 -5.8612488e+07 8.60e+04 7.19e+05 -3.8 2.49e+06 - 2.94e-01 2.08e-02h 1\n", + " 26 -5.8740061e+07 4.93e+04 1.28e+05 -3.8 2.43e+06 - 1.96e-01 4.35e-01h 1\n", + " 27 -5.8740292e+07 4.91e+04 3.28e+07 -3.8 9.94e+05 - 6.54e-01 4.63e-03h 1\n", + " 28 -5.8788497e+07 5.30e+03 1.02e+07 -3.8 9.26e+05 - 8.88e-01 1.00e+00h 1\n", + " 29 -5.8643006e+07 5.29e+03 1.65e+07 -3.8 2.35e+07 - 9.21e-04 1.55e-03h 7\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30 -5.7470132e+07 2.03e+02 1.15e+09 -3.8 2.85e+05 - 9.22e-06 1.00e+00h 1\n", + " 31 -5.7582403e+07 9.77e+00 1.14e+08 -3.8 1.63e+04 - 9.98e-01 1.00e+00h 1\n", + " 32 -7.8527164e+07 1.13e+05 8.45e+06 -3.8 4.35e+06 - 4.64e-01 9.37e-01f 1\n", + " 33 -7.8529326e+07 1.13e+05 8.45e+06 -3.8 5.31e+06 - 7.75e-01 1.16e-04h 1\n", + " 34 -7.9550162e+07 1.33e+05 6.60e+06 -3.8 4.19e+06 - 8.67e-01 2.18e-01h 1\n", + " 35 -7.9541163e+07 1.33e+05 6.57e+06 -3.8 3.58e+05 - 1.65e-03 4.97e-03h 1\n", + " 36 -7.9533059e+07 1.32e+05 6.54e+06 -3.8 1.15e+05 -7.8 1.26e-06 4.40e-03h 1\n", + " 37 -7.9485981e+07 1.29e+05 6.39e+06 -3.8 6.04e+04 -8.3 9.51e-01 2.34e-02h 1\n", + " 38 -7.8379026e+07 4.89e+04 2.42e+06 -3.8 1.52e+05 - 6.47e-01 6.21e-01h 1\n", + " 39 -7.8367473e+07 4.80e+04 2.38e+06 -3.8 5.52e+04 -8.8 3.60e-03 1.70e-02h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 -7.7618174e+07 1.40e+02 3.78e+03 -3.8 3.11e+04 -9.2 1.00e+00 1.00e+00h 1\n", + " 41 -7.7621799e+07 9.06e-01 7.63e-02 -3.8 4.67e+03 - 1.00e+00 1.00e+00h 1\n", + " 42 -7.7699327e+07 1.63e+02 9.22e-03 -3.8 6.11e+04 - 1.00e+00 1.00e+00f 1\n", + " 43 -7.7700167e+07 4.77e-02 2.09e-06 -3.8 1.01e+04 - 1.00e+00 1.00e+00h 1\n", + " 44 -7.7700500e+07 3.88e+00 3.43e+02 -5.7 9.57e+04 - 9.77e-01 1.00e+00h 1\n", + " 45 -7.7700531e+07 4.16e-01 1.40e-03 -5.7 2.26e+04 - 1.00e+00 9.06e-01h 1\n", + " 46 -7.7700531e+07 5.03e-04 3.89e-08 -5.7 9.81e+02 - 1.00e+00 1.00e+00f 1\n", + " 47 -7.7700536e+07 9.48e-04 2.13e-01 -8.6 1.62e+03 - 1.00e+00 9.99e-01h 1\n", + " 48 -7.7700536e+07 5.82e-09 1.08e-10 -8.6 1.88e+00 - 1.00e+00 1.00e+00f 1\n", + " 49 -7.7700536e+07 9.31e-09 6.97e-11 -10.9 2.16e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 49\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -1.2012103932708935e+02 -7.7700535938862920e+07\n", + "Dual infeasibility......: 6.9703019509761989e-11 4.5087538392986020e-05\n", + "Constraint violation....: 1.0186340659856796e-10 9.3132257461547852e-09\n", + "Variable bound violation: 5.1274423640279565e-06 5.1274423640279565e-06\n", + "Complementarity.........: 1.4074777602003514e-11 9.1042982063954507e-06\n", + "Overall NLP error.......: 1.0186340659856796e-10 4.5087538392986020e-05\n", + "\n", + "\n", + "Number of objective function evaluations = 63\n", + "Number of objective gradient evaluations = 50\n", + "Number of equality constraint evaluations = 63\n", + "Number of inequality constraint evaluations = 63\n", + "Number of equality constraint Jacobian evaluations = 51\n", + "Number of inequality constraint Jacobian evaluations = 51\n", + "Number of Lagrangian Hessian evaluations = 49\n", + "Total seconds in IPOPT = 0.048\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Optimal solution process results:\n", + "\n", + "\n", + "Extent of reaction: 269.280544787992\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.8500000099999546\n", + "Reactor duty (MW): -51.36357357754579\n", + "Duty from Reaction (MW)): 24.407588579583596\n", + "Turbine work (MW): -1.9904899177794853\n", + "Mixer outlet temperature (C)): 20.05171421375337\n", + "Compressor outlet temperature (C)): 20.051714213753485\n", + "Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 231.85000468716584\n", + "Turbine outlet temperature (C)): 139.85888172675567\n", + "Turbine outlet pressure (Pa)): 1427653.3547820917\n", + "Cooler outlet temperature (C)): 52.56999709299214\n", + "Flash outlet temperature (C)): 134.0\n", + "Methanol recovery(%): 92.80355474657543\n", + "annualized capital cost ($/year) = 235547.18924473305\n", + "operating cost ($/year) = 451663512.6847631\n", + "sales ($/year) = 113381889876.90088\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 77700535.9388629\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 165.54\n", + " Total Mole Fraction CH4 dimensionless 5.7630e-06\n", + " Total Mole Fraction CO dimensionless 0.28706\n", + " Total Mole Fraction H2 dimensionless 0.59587\n", + " Total Mole Fraction CH3OH dimensionless 0.11706\n", + " Molar Enthalpy joule / mole -52313.\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 249.90\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3792e+05\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "opt_res = solver.solve(m, tee=True)\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, - "scrolled": false - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, the process achieves a much greater revenue as a result of increasing conversion and lowering the inlet temperature to the Flash unit to encourage methanol recovery in the liquid phase. The results show a slight increase in equipment and operating costs from these changes, as well as a small loss of methanol in the exhaust." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 4. Problem Statement - Analyzing Benefit of Recycling Flash Vapor\n", + "\n", + "To increase the efficiency of the process as well as overall methanol production and revenue, we can add a recycle stream to send most of the Flash vapor back to the start of the process. This will reduce methanol loss in the exhaust and increase feed utilization, resulting in increased operating costs and increased production (revenue) at the same conversion. Note that for conversions less than 100%, a simulation with no purge will never converge due to accumulation of gases within the system. Therefore, to ensure we close the mass balance we set a lower bound at 10% purge from the Flash vapor to the exhaust. We expect to see a marginal increase in operating costs due to increased flow, and a much larger increase in overall production resulting in a higher total revenue.\n", + "\n", + "By adding a recycle to the flowsheet, we significantly decrease the tractability of the problem and require a better initial guess. The SequentialDecomposition algorithm automatically determines a stream to *tear*, or use to break the solve loop, and iterates from a set of user-supplied initial guesses until converging on the optimal solution. The code below calls an initialization method to automatically determine the tear stream. See the initialization method of `methanol_flowsheet_w_recycle.py` for further details Sequential Decomposition scheme.\n", + "\n", + "For given raw material flows and optimal reactor conditions, we will calculate the extent of reaction, relevant process results including reactor duty and turbine duty, methanol recovery, and relevant economic results including annual revenue.\n", + "\n", + "## 4.1. Main Inputs: \n", + "- Raw material inlets (F - mol/s, P - Pa, h - j/mol, x - mole fraction)\n", + "- Pre-reactor compressor outlet pressure (Pa)\n", + "- Pre-reactor heater outlet temperature (K)\n", + "\n", + "## 4.2. Main Outputs:\n", + "- Extent of reaction (mol/s)\n", + "- Reactor duty (W)\n", + "- Compressor duty (W)\n", + "- Turbine duty (W)\n", + "- Methanol recovery (%)\n", + "- Purge percentage (%)\n", + "- Annual revenue (USD/year)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1227\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 772\n", - "\n", - "Total number of variables............................: 406\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 336\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 406\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8497869e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.9074832e+07 5.76e+04 4.22e+03 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", - " 2 -2.9080637e+07 5.71e+02 3.82e+03 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", - " 3 -2.9080695e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", - " 4 -2.9080695e+07 9.31e-10 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 4\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -4.4953175283791907e+01 -2.9080695361147854e+07\n", - "Dual infeasibility......: 2.4946824403693549e-06 1.6138370562967401e+00\n", - "Constraint violation....: 4.5474735088646412e-12 9.3132257461547852e-10\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 4.5474735088646412e-12 1.6138370562967401e+00\n", - "\n", - "\n", - "Number of objective function evaluations = 5\n", - "Number of objective gradient evaluations = 5\n", - "Number of equality constraint evaluations = 5\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 5\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 4\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.006\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "code", + "execution_count": 11, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.517374100Z", + "start_time": "2026-02-20T21:01:09.509320Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(\"methanol_flowsheet_recycle.png\")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Initial solution process results:\n", - "\n", - "\n", - "Extent of reaction: 237.6064180604515\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.75\n", - "Reactor duty (MW): -45.22029794711382\n", - "Duty from Reaction (MW)): 21.536645732999325\n", - "Compressor work (MW): -2.5668711294294714e-15\n", - "Turbine work (MW): -0.959378502391431\n", - "Feed Mixer outlet temperature (C)): 20.051714213753144\n", - "Recycle Mixer outlet temperature (C)): 20.056485612776214\n", - "Feed Compressor outlet temperature (C)): 20.0564856127761\n", - "Feed Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 234.0\n", - "Turbine outlet temperature (C)): 192.87840947667888\n", - "Turbine outlet pressure (Pa)): 3100000.0\n", - "Cooler outlet temperature (C)): 134.0\n", - "Flash outlet temperature (C)): 134.0\n", - "Purge percentage (amount of vapor vented to exhaust): 99.99 %\n", - "Methanol recovery(%): 60.005984934911716\n", - "annualized capital cost ($/year) = 219794.2325658716\n", - "operating cost ($/year) = 380711692.18369955\n", - "sales ($/year) = 64691081725.72807\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 29080695.36114784\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 336.21\n", - " Total Mole Fraction CH4 dimensionless 2.8375e-06\n", - " Total Mole Fraction CO dimensionless 0.23555\n", - " Total Mole Fraction H2 dimensionless 0.48181\n", - " Total Mole Fraction CH3OH dimensionless 0.28263\n", - " Molar Enthalpy joule / mole -80218.\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 142.58\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3813e+05\n", - " Pressure pascal 3.1000e+06\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "add_costing(m) # re-solve with costing equations\n", - "print()\n", - "results2 = solver.solve(m, tee=True)\n", - "\n", - "print(\"Initial solution process results:\")\n", - "report(m) # display initial solution results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions, including a purge between 10-50% of flash vapor. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:25.618074700Z", - "start_time": "2026-02-20T21:01:25.159753600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-20T21:02:38.069628Z", - "iopub.status.busy": "2026-02-20T21:02:38.069628Z", - "iopub.status.idle": "2026-02-20T21:02:38.463172Z", - "shell.execute_reply": "2026-02-20T21:02:38.463172Z" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 5. Import and Solve Recycle Flowsheet\n", + "## 5.1 Import Pyomo and IDAES Libraries\n", + "As we are rebuilding the model, we need to import require Pyomo and IDAES libraries:" + ] }, - "scrolled": false - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Solving optimization problem...\n", - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 12, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:09.534388600Z", + "start_time": "2026-02-20T21:01:09.517374100Z" + } + }, + "outputs": [], + "source": [ + "import pytest\n", + "import os\n", + "\n", + "# Import Pyomo libraries\n", + "from pyomo.environ import (\n", + " Constraint,\n", + " Objective,\n", + " Var,\n", + " Expression,\n", + " Param,\n", + " ConcreteModel,\n", + " TransformationFactory,\n", + " value,\n", + " maximize,\n", + " units as pyunits,\n", + ")\n", + "from pyomo.environ import TerminationCondition\n", + "from pyomo.network import Arc, SequentialDecomposition\n", + "\n", + "# Import IDAES core libraries\n", + "from idaes.core import FlowsheetBlock\n", + "from idaes.core.solvers import get_solver\n", + "from idaes.core.util import scaling as iscale\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "from idaes.core.util.initialization import propagate_state\n", + "\n", + "# Import required models\n", + "\n", + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "\n", + "from idaes_examples.mod.methanol import methanol_ideal_VLE as thermo_props_VLE\n", + "from idaes_examples.mod.methanol import methanol_ideal_vapor as thermo_props_vapor\n", + "from idaes_examples.mod.methanol import methanol_reactions as reaction_props\n", + "\n", + "from idaes.models.unit_models import (\n", + " Feed,\n", + " Mixer,\n", + " Heater,\n", + " Compressor,\n", + " Turbine,\n", + " StoichiometricReactor,\n", + " Flash,\n", + " Separator as Splitter,\n", + " Product,\n", + ")\n", + "from idaes.models.unit_models.mixer import MomentumMixingType\n", + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core import UnitModelCostingBlock\n", + "from idaes.models.costing.SSLW import SSLWCosting\n", + "import idaes.logger as idaeslog\n", + "\n", + "# import flowsheet functions\n", + "from methanol_flowsheet_w_recycle import (\n", + " build_model,\n", + " set_inputs,\n", + " scale_flowsheet,\n", + " initialize_flowsheet,\n", + " add_costing,\n", + " report,\n", + ")" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5.2 Build and Solve Recycle Flowsheet\n", + "As before, we will first build the flowsheet, set required inputs, initialize and solve a square problem. Recycling methanol to pre-reactor blocks complicates VLE calculations, and limiting VLE calculations to the Flash unit and liquid Product block greatly increases tractability during initialization. All initial feed and unit specifications are identical to the non-recycle case; the Sequential Decomposition algorithm automatically selects the compressor feed as the tear stream and uses \"no recycle\" results as a first guess. In the output below, the solver solves all units and then resolves select blocks with updated inlet results, followed by a full flowsheet solve:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n", - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1236\n", - "Number of nonzeros in inequality constraint Jacobian.: 10\n", - "Number of nonzeros in Lagrangian Hessian.............: 779\n", - "\n", - "Total number of variables............................: 410\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 337\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 405\n", - "Total number of inequality constraints...............: 10\n", - " inequality constraints with only lower bounds: 5\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 5\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -2.8497829e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -2.8431127e+07 2.74e+04 9.77e+01 -1.0 8.82e+06 - 4.99e-02 1.94e-02h 1\n", - " 2 -2.8430719e+07 2.74e+04 7.81e+02 -1.0 8.52e+06 - 3.76e-02 1.99e-04h 1\n", - " 3 -2.8524903e+07 2.48e+04 1.61e+05 -1.0 6.46e+06 - 2.49e-04 9.25e-02f 1\n", - " 4 -2.8526723e+07 2.48e+04 1.61e+05 -1.0 5.76e+06 - 5.84e-02 9.84e-04h 1\n", - " 5 -2.8554206e+07 2.48e+04 1.60e+05 -1.0 1.49e+07 - 3.32e-03 8.96e-04h 1\n", - " 6 -2.9123967e+07 2.43e+04 1.52e+05 -1.0 1.49e+07 - 1.23e-01 1.84e-02f 1\n", - " 7 -2.9208690e+07 2.43e+04 1.51e+05 -1.0 9.71e+06 - 2.32e-02 2.78e-03h 1\n", - " 8 -3.0003175e+07 2.36e+04 1.08e+06 -1.0 9.31e+06 - 1.92e-01 2.61e-02h 1\n", - " 9 -3.1468200e+07 2.25e+04 1.09e+06 -1.0 8.71e+06 - 6.69e-02 4.91e-02f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -3.1583903e+07 2.24e+04 1.14e+07 -1.0 5.51e+06 - 3.91e-01 3.89e-03h 1\n", - " 11 -4.3112078e+07 3.08e+04 5.71e+06 -1.0 5.49e+06 - 1.57e-01 3.86e-01f 1\n", - " 12 -4.3711661e+07 4.53e+04 5.09e+06 -1.0 3.67e+06 - 8.46e-02 2.88e-02h 1\n", - " 13 -4.3718221e+07 4.53e+04 1.94e+06 -1.0 3.57e+06 - 5.81e-01 3.23e-04h 1\n", - " 14 -4.3760623e+07 4.51e+04 4.16e+07 -1.0 3.56e+06 - 4.25e-01 5.93e-03h 1\n", - " 15 -4.4646398e+07 7.99e+04 5.37e+07 -1.0 3.54e+06 - 6.75e-01 1.23e-01h 4\n", - " 16 -6.6613749e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", - " 17 -6.5999969e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", - " 18 -6.5249518e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", - " 19 -6.4064695e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -6.4051103e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", - " 21 -6.5080976e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", - " 22 -7.5335243e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", - " 23 -7.4658996e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", - " 24 -7.4649764e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", - " 25 -7.4613845e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", - " 26 -7.4421363e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", - " 27 -7.4390154e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n", - " 28 -7.2740081e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", - " 29 -7.2726278e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 30 -7.2726419e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", - " 31 -8.6665745e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", - " 32 -8.6649468e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", - " 33 -8.6148813e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.44e-02 1.00e+00h 1\n" - ] + "cell_type": "code", + "execution_count": 13, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.393968500Z", + "start_time": "2026-02-20T21:01:09.535877100Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unit degrees of freedom\n", + "M101 0\n", + "C101 1\n", + "H101 1\n", + "R101 2\n", + "T101 2\n", + "H102 1\n", + "F101 2\n", + "M102 0\n", + "S101 1\n", + "Total DOF: 24\n", + "DOF after streams specified: 10\n", + "DOF after units specified: 0\n", + "\n", + "Tear Stream:\n", + "fs.s02 : fs.M102.outlet to fs.C101.inlet\n", + "\n", + "Calculation order:\n", + "fs.H2\n", + "fs.M101\n", + "fs.R101\n", + "fs.T101\n", + "fs.H102\n", + "fs.F101\n", + "fs.S101\n", + "fs.EXHAUST\n", + "\n", + "Initial DOF = 0\n", + "Solving fs.H2\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CO\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.C101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.R101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 15 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.T101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 9\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 23 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H102\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.F101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 42 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.S101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 12 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CH3OH\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.EXHAUST\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M102\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.H2\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CO\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.M101\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 6 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 14\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 18 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.EXHAUST\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 4 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Solving fs.CH3OH\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 16\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 8\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "DOF = 0\n", + "Final DOF = 0\n", + "DOF before solve: 0\n", + "\n", + "Solving initial problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1211\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 768\n", + "\n", + "Total number of variables............................: 397\n", + " variables with only lower bounds: 41\n", + " variables with lower and upper bounds: 336\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 397\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 2.79e+04 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 2.79e+02 4.22e+03 -1.0 1.96e+03 - 9.90e-01 9.90e-01h 1\n", + " 2 0.0000000e+00 2.77e+00 3.86e+03 -1.0 2.03e+01 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 7.44e-06 1.01e+03 -1.0 2.01e-01 - 9.90e-01 1.00e+00h 1\n", + " 4 0.0000000e+00 2.10e-09 9.89e+04 -1.0 1.19e-07 - 9.90e-01 1.00e+00h 1\n", + " 5 0.0000000e+00 2.10e-09 0.00e+00 -1.0 2.51e-08 - 9.91e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 5\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 6.7595993318865371e-14 2.0954757928848267e-09\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 6.7595993318865371e-14 2.0954757928848267e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 6\n", + "Number of objective gradient evaluations = 6\n", + "Number of equality constraint evaluations = 6\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 6\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 5\n", + "Total seconds in IPOPT = 0.009\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "source": [ + "# Build and solve flowsheet\n", + "solver = get_solver() # IPOPT\n", + "optarg = {\"tol\": 1e-6, \"max_iter\": 100}\n", + "solver.options = optarg\n", + "\n", + "m = ConcreteModel() # create a new model so we may reference 'm' below\n", + "build_model(m) # build flowsheet\n", + "set_inputs(m) # unit and stream specifications\n", + "scale_flowsheet(m) # flowsheet and unit model level scaling\n", + "\n", + "# let the solver determine the tear stream\n", + "initialize_flowsheet(m) # rigorous initialization scheme\n", + "\n", + "print(\"DOF before solve: \", degrees_of_freedom(m))\n", + "print()\n", + "print(\"Solving initial problem...\")\n", + "results = solver.solve(m, tee=True)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 34 -8.6163785e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", - " 35 -8.6204319e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", - " 36 -8.6333114e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", - " 37 -8.6713987e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", - " 38 -8.7245785e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", - " 39 -9.0563354e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 40 -9.9476688e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", - " 41 -9.9478624e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", - " 42 -1.0299591e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", - " 43 -1.0299655e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", - " 44 -1.0436244e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", - " 45 -1.0441522e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", - " 46 -1.0438806e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", - " 47 -1.0435495e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", - " 48 -1.0426618e+08 2.01e+03 2.19e+01 -3.8 1.81e+06 - 1.20e-01 1.00e+00h 1\n", - " 49 -1.0426992e+08 2.91e+02 3.40e-01 -3.8 6.45e+04 -13.1 1.00e+00 9.64e-01h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.80e+06 - 5.54e-03 2.57e-01h 1\n", - " 51 -1.0427055e+08 2.92e+02 3.97e+02 -3.8 3.24e+06 - 1.33e-01 1.97e-02h 1\n", - " 52 -1.0427008e+08 1.05e+02 1.15e+05 -3.8 2.71e+04 - 7.76e-04 1.00e+00f 1\n", - " 53 -1.0427044e+08 9.41e+01 7.74e+04 -3.8 4.75e+04 -12.6 1.00e+00 3.26e-01h 2\n", - " 54 -1.0427081e+08 9.98e+01 6.24e+04 -3.8 8.03e+04 -13.1 1.00e+00 1.91e-01h 2\n", - " 55 -1.0427080e+08 8.21e-01 1.24e+00 -3.8 7.52e+04 - 1.00e+00 1.00e+00h 1\n", - " 56 -1.0427114e+08 2.09e+01 2.34e+02 -3.8 3.16e+04 -12.7 1.00e+00 4.65e-01h 2\n", - " 57 -1.0427107e+08 4.98e-01 5.37e+00 -3.8 1.61e+04 - 1.00e+00 1.00e+00h 1\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5.3 Flowsheet Costing and Optimization\n", + "Now that we have a well-initialized and solved flowsheet, we can add process economics and optimize the revenue. We utilize IDAES costing tools to calculate reactor and flash vessel capital cost, and implement surrogate models to account for heat exchanger capital costs, reactor operating costs and utility costs for heating, cooling and electricity. As before, revenue is determined from total liquid methanol sales, operating costs, annualized capital costs and feed raw material costs. The flowsheet report method returns key process results, which are updated for new results with the presence of a recycle stream:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 58 -1.0427121e+08 3.58e+00 1.04e+03 -3.8 1.22e+04 -12.3 1.00e+00 4.79e-01h 2\n", - " 59 -1.0427120e+08 8.56e-03 3.90e+00 -3.8 1.47e+03 - 1.00e+00 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 60 -1.0427265e+08 3.69e+02 2.06e+03 -3.8 6.13e+04 -12.7 1.00e+00 1.00e+00f 1\n", - " 61 -1.0427267e+08 8.82e-03 8.41e-01 -3.8 2.14e+04 - 1.00e+00 1.00e+00h 1\n", - " 62 -1.0427488e+08 8.81e+02 4.71e+03 -3.8 9.30e+04 -13.2 9.57e-01 1.00e+00h 1\n", - " 63 -1.0427489e+08 1.12e-02 8.43e+03 -3.8 2.41e+04 - 4.26e-01 1.00e+00h 1\n", - " 64 -1.0427588e+08 1.77e+02 2.25e+02 -3.8 4.16e+04 -12.8 1.00e+00 1.00e+00h 1\n", - " 65 -1.0427569e+08 7.17e+00 2.18e+02 -3.8 9.45e+03 - 8.56e-01 1.00e+00h 1\n", - " 66 -1.0427569e+08 3.81e-04 1.34e+03 -3.8 7.69e+02 - 3.56e-01 1.00e+00h 1\n", - " 67 -1.0427568e+08 5.99e-04 1.01e+02 -3.8 7.28e+01 - 6.32e-01 1.00e+00h 1\n", - " 68 -1.0427568e+08 5.44e-04 1.32e+02 -3.8 6.86e+01 - 5.69e-01 1.00e+00h 1\n", - " 69 -1.0427569e+08 3.30e-03 2.05e+01 -3.8 2.50e+02 - 6.00e-01 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 70 -1.0427569e+08 1.33e-05 2.19e+01 -3.8 2.05e+02 - 5.83e-01 1.00e+00h 1\n", - " 71 -1.0427569e+08 1.09e-03 3.63e+00 -3.8 5.68e+02 - 5.94e-01 1.00e+00f 1\n", - " 72 -1.0427569e+08 6.75e-04 3.84e+00 -3.8 1.21e+03 - 5.81e-01 1.00e+00h 1\n", - " 73 -1.0427569e+08 6.52e-03 6.49e-01 -3.8 3.03e+03 - 5.80e-01 1.00e+00h 1\n", - " 74 -1.0427570e+08 3.77e-02 6.80e-01 -3.8 7.51e+03 - 5.69e-01 1.00e+00h 1\n", - " 75 -1.0427573e+08 2.57e-01 1.17e-01 -3.8 1.96e+04 - 5.45e-01 1.00e+00h 1\n", - " 76 -1.0427580e+08 2.17e+00 1.46e-01 -3.8 5.66e+04 - 4.91e-01 1.00e+00h 1\n", - " 77 -1.0427608e+08 3.10e+01 6.00e-02 -3.8 2.13e+05 - 3.77e-01 1.00e+00h 1\n", - " 78 -1.0427817e+08 1.76e+03 5.49e-01 -3.8 1.56e+06 - 1.85e-01 1.00e+00h 1\n", - " 79 -1.0427835e+08 1.67e+03 6.12e-01 -3.8 1.75e+06 - 9.50e-01 6.05e-02h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 80 -1.0427838e+08 3.76e-01 2.22e-04 -3.8 9.99e+04 - 1.00e+00 1.00e+00h 1\n", - " 81 -1.0427881e+08 2.24e+00 1.80e+02 -5.7 8.49e+04 - 9.88e-01 1.00e+00h 1\n", - " 82 -1.0427883e+08 9.31e-02 1.16e-03 -5.7 1.69e+04 - 1.00e+00 9.65e-01h 1\n", - " 83 -1.0427883e+08 1.60e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", - " 84 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", - " 85 -1.0427884e+08 5.59e-09 2.35e-13 -8.6 7.18e-01 - 1.00e+00 1.00e+00h 1\n", - " 86 -1.0427884e+08 2.79e-09 9.30e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 86\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -1.6119507851267775e+02 -1.0427883997848792e+08\n", - "Dual infeasibility......: 9.2995983076271742e-12 6.0160107413515216e-06\n", - "Constraint violation....: 1.0913936421275139e-10 2.7939677238464355e-09\n", - "Complementarity.........: 1.4067955341342552e-11 9.1007124870068398e-06\n", - "Overall NLP error.......: 1.0913936421275139e-10 9.1007124870068398e-06\n", - "\n", - "\n", - "Number of objective function evaluations = 118\n", - "Number of objective gradient evaluations = 87\n", - "Number of equality constraint evaluations = 118\n", - "Number of inequality constraint evaluations = 118\n", - "Number of equality constraint Jacobian evaluations = 87\n", - "Number of inequality constraint Jacobian evaluations = 87\n", - "Number of Lagrangian Hessian evaluations = 86\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.092\n", - "Total CPU secs in NLP function evaluations = 0.014\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "code", + "execution_count": 15, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:12.612557100Z", + "start_time": "2026-02-20T21:01:12.405029Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 98\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=100\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1227\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 772\n", + "\n", + "Total number of variables............................: 406\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 336\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 406\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8497869e+07 9.10e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.9074832e+07 5.76e+04 4.22e+03 -1.0 1.20e+05 - 5.03e-02 9.90e-01h 1\n", + " 2 -2.9080637e+07 5.71e+02 3.82e+03 -1.0 5.72e+04 - 9.81e-01 9.90e-01h 1\n", + " 3 -2.9080695e+07 5.22e-05 1.00e+03 -1.0 5.67e+02 - 9.90e-01 1.00e+00h 1\n", + " 4 -2.9080695e+07 1.05e-09 9.90e+04 -1.0 5.22e-05 - 9.90e-01 1.00e+00h 1\n", + " 5 -2.9080695e+07 1.16e-09 9.85e+02 -1.0 2.19e-08 - 9.90e-01 1.00e+00h 1\n", + " 6 -2.9080695e+07 9.31e-10 7.17e+04 -1.7 1.59e-08 - 9.91e-01 1.00e+00h 1\n", + " 7 -2.9080695e+07 9.31e-10 2.00e-07 -1.7 2.11e-08 - 1.00e+00 1.00e+00h 1\n", + " 8 -2.9080695e+07 9.31e-10 1.01e-09 -5.7 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + " 9 -2.9080695e+07 9.31e-10 3.69e-13 -8.6 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -2.9080695e+07 9.31e-10 2.90e-13 -10.9 1.43e-08 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 10\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -4.4953175283792277e+01 -2.9080695361147840e+07\n", + "Dual infeasibility......: 2.8986503540945592e-13 1.8751682695104163e-07\n", + "Constraint violation....: 4.5474735088646412e-12 9.3132257461547852e-10\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.4052801174098027e-11 9.0909090922898242e-06\n", + "Overall NLP error.......: 1.4052801174098027e-11 9.0909090922898242e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 11\n", + "Number of objective gradient evaluations = 11\n", + "Number of equality constraint evaluations = 11\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 11\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 10\n", + "Total seconds in IPOPT = 0.017\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Initial solution process results:\n", + "\n", + "\n", + "Extent of reaction: 237.60641806045152\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : 0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.75\n", + "Reactor duty (MW): -45.22029794711383\n", + "Duty from Reaction (MW)): 21.536645732999325\n", + "Compressor work (MW): -3.72291430867571e-35\n", + "Turbine work (MW): -0.9593785023914099\n", + "Feed Mixer outlet temperature (C)): 20.0517142137532\n", + "Recycle Mixer outlet temperature (C)): 20.056485612776157\n", + "Feed Compressor outlet temperature (C)): 20.056485612776157\n", + "Feed Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 234.0\n", + "Turbine outlet temperature (C)): 192.8784094766802\n", + "Turbine outlet pressure (Pa)): 3100000.0\n", + "Cooler outlet temperature (C)): 134.0\n", + "Flash outlet temperature (C)): 134.0\n", + "Purge percentage (amount of vapor vented to exhaust): 99.99 %\n", + "Methanol recovery(%): 60.0059849349117\n", + "annualized capital cost ($/year) = 219794.23256587266\n", + "operating cost ($/year) = 380711692.1836992\n", + "sales ($/year) = 64691081725.72806\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 29080695.361147825\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 336.21\n", + " Total Mole Fraction CH4 dimensionless 2.8375e-06\n", + " Total Mole Fraction CO dimensionless 0.23555\n", + " Total Mole Fraction H2 dimensionless 0.48181\n", + " Total Mole Fraction CH3OH dimensionless 0.28263\n", + " Molar Enthalpy joule / mole -80218.\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 142.58\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3813e+05\n", + " Pressure pascal 3.1000e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "add_costing(m) # re-solve with costing equations\n", + "print()\n", + "results2 = solver.solve(m, tee=True)\n", + "\n", + "print(\"Initial solution process results:\")\n", + "report(m) # display initial solution results" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", - "component keys that are not exported as part of the NL file. Skipping.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's unfix some specifications and determine an optimal revenue. We set bounds on our decision variables to constrain our objective to physical and economically sensible solutions, including a purge between 10-50% of flash vapor. The pre-reactor section mixes the feeds and brings the reactants to optimal temperature and pressure, and we only unfix downstream unit specifications:" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", - "that are not Var, Constraint, Objective, or the model. Skipping.\n" - ] + "cell_type": "code", + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:13.760944100Z", + "start_time": "2026-02-20T21:01:12.626378Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Solving optimization problem...\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1236\n", + "Number of nonzeros in inequality constraint Jacobian.: 10\n", + "Number of nonzeros in Lagrangian Hessian.............: 779\n", + "\n", + "Total number of variables............................: 410\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 337\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 405\n", + "Total number of inequality constraints...............: 10\n", + " inequality constraints with only lower bounds: 5\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 5\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -2.8497829e+07 2.79e+04 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -2.8431127e+07 2.74e+04 9.77e+01 -1.0 8.82e+06 - 4.99e-02 1.94e-02h 1\n", + " 2 -2.8430719e+07 2.74e+04 7.81e+02 -1.0 8.52e+06 - 3.76e-02 1.99e-04h 1\n", + " 3 -2.8524903e+07 2.48e+04 1.61e+05 -1.0 6.46e+06 - 2.49e-04 9.25e-02f 1\n", + " 4 -2.8526723e+07 2.48e+04 1.61e+05 -1.0 5.76e+06 - 5.84e-02 9.84e-04h 1\n", + " 5 -2.8554206e+07 2.48e+04 1.60e+05 -1.0 1.49e+07 - 3.32e-03 8.96e-04h 1\n", + " 6 -2.9123967e+07 2.43e+04 1.52e+05 -1.0 1.49e+07 - 1.23e-01 1.84e-02f 1\n", + " 7 -2.9208690e+07 2.43e+04 1.51e+05 -1.0 9.71e+06 - 2.32e-02 2.78e-03h 1\n", + " 8 -3.0003175e+07 2.36e+04 1.08e+06 -1.0 9.31e+06 - 1.92e-01 2.61e-02h 1\n", + " 9 -3.1468200e+07 2.25e+04 1.09e+06 -1.0 8.71e+06 - 6.69e-02 4.91e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -3.1583903e+07 2.24e+04 1.14e+07 -1.0 5.51e+06 - 3.91e-01 3.89e-03h 1\n", + " 11 -4.3112078e+07 3.08e+04 5.71e+06 -1.0 5.49e+06 - 1.57e-01 3.86e-01f 1\n", + " 12 -4.3711661e+07 4.53e+04 5.09e+06 -1.0 3.67e+06 - 8.46e-02 2.88e-02h 1\n", + " 13 -4.3718221e+07 4.53e+04 1.94e+06 -1.0 3.57e+06 - 5.81e-01 3.23e-04h 1\n", + " 14 -4.3760623e+07 4.51e+04 4.16e+07 -1.0 3.56e+06 - 4.25e-01 5.93e-03h 1\n", + " 15 -4.4646398e+07 7.99e+04 5.37e+07 -1.0 3.54e+06 - 6.75e-01 1.23e-01h 4\n", + " 16 -6.6613710e+07 4.71e+04 6.18e+06 -1.0 3.14e+06 - 7.83e-01 9.90e-01H 1\n", + " 17 -6.5999923e+07 4.71e+04 3.10e+06 -1.0 2.01e+07 - 3.61e-03 3.25e-03h 5\n", + " 18 -6.5249462e+07 4.72e+04 3.12e+07 -1.0 1.74e+07 - 4.59e-05 4.34e-03h 5\n", + " 19 -6.4064651e+07 2.26e+03 9.68e+06 -1.0 8.00e+04 - 3.33e-04 9.87e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 -6.4051060e+07 1.77e+03 8.53e+03 -1.0 2.66e+03 - 9.89e-01 1.00e+00h 1\n", + " 21 -6.5080931e+07 1.26e+03 4.14e+05 -1.0 1.04e+05 - 9.50e-01 9.92e-01f 1\n", + " 22 -7.5335226e+07 1.38e+05 3.86e+06 -1.0 1.20e+06 - 2.39e-01 1.00e+00f 1\n", + " 23 -7.4658976e+07 9.99e+04 2.12e+06 -1.0 1.07e+05 -4.0 9.90e-01 2.78e-01h 1\n", + " 24 -7.4649744e+07 9.94e+04 2.08e+06 -1.0 7.73e+04 -4.5 5.39e-01 5.23e-03h 1\n", + " 25 -7.4613824e+07 9.73e+04 2.01e+06 -1.0 7.23e+04 -5.0 1.00e+00 2.08e-02h 1\n", + " 26 -7.4421345e+07 8.62e+04 1.78e+06 -1.0 7.09e+04 -5.4 5.88e-01 1.14e-01h 1\n", + " 27 -7.4390136e+07 8.46e+04 1.75e+06 -1.0 7.84e+04 -5.9 1.21e-02 1.83e-02h 1\n", + " 28 -7.2740056e+07 3.01e+02 1.73e+06 -1.0 1.09e+05 -6.4 1.05e-04 1.00e+00h 1\n", + " 29 -7.2726253e+07 1.44e-01 6.68e+02 -1.0 5.95e+02 -6.9 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30 -7.2726394e+07 7.97e-05 2.12e+01 -1.7 1.63e+02 -7.3 1.00e+00 1.00e+00f 1\n", + " 31 -8.6665441e+07 8.89e+03 9.70e+05 -2.5 5.14e+06 - 2.89e-02 5.94e-01f 1\n", + " 32 -8.6649164e+07 8.59e+03 6.03e+05 -2.5 1.66e+04 -7.8 9.58e-01 3.35e-02h 1\n", + " 33 -8.6148490e+07 1.45e+01 6.46e+04 -2.5 2.26e+04 -8.3 8.45e-02 1.00e+00h 1\n", + " 34 -8.6163461e+07 4.53e-03 1.68e+00 -2.5 3.37e+03 -8.8 1.00e+00 1.00e+00h 1\n", + " 35 -8.6203995e+07 4.58e-02 7.40e-02 -2.5 1.03e+04 -9.2 1.00e+00 1.00e+00f 1\n", + " 36 -8.6332790e+07 3.92e-01 1.69e+02 -3.8 3.04e+04 -9.7 1.00e+00 1.00e+00f 1\n", + " 37 -8.6713663e+07 3.42e+00 4.46e-01 -3.8 9.15e+04 -10.2 1.00e+00 1.00e+00f 1\n", + " 38 -8.7245413e+07 7.78e+00 1.64e+00 -3.8 2.74e+05 -10.7 1.00e+00 4.68e-01f 1\n", + " 39 -9.0562979e+07 2.18e+02 6.58e+00 -3.8 8.00e+05 -11.2 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 -9.9476648e+07 6.32e+02 4.50e+01 -3.8 2.39e+06 -11.6 1.00e+00 9.22e-01f 1\n", + " 41 -9.9478583e+07 6.32e+02 4.50e+01 -3.8 5.59e+06 -12.1 1.12e-01 8.94e-05h 1\n", + " 42 -1.0299584e+08 3.80e+04 1.01e+02 -3.8 7.08e+06 -12.6 4.04e-01 1.44e-01f 1\n", + " 43 -1.0299648e+08 3.80e+04 1.08e+02 -3.8 1.39e+06 - 6.91e-01 2.06e-04h 1\n", + " 44 -1.0436243e+08 3.39e+05 1.55e+01 -3.8 2.01e+06 - 1.00e+00 1.00e+00h 1\n", + " 45 -1.0441521e+08 3.19e+05 1.27e+02 -3.8 4.87e+06 - 9.54e-01 8.06e-02h 1\n", + " 46 -1.0438805e+08 2.70e+05 9.30e+01 -3.8 1.25e+07 - 2.30e-01 1.54e-01h 1\n", + " 47 -1.0435494e+08 2.01e+05 1.05e+01 -3.8 9.64e+05 - 8.19e-01 2.54e-01h 1\n", + " 48 -1.0426618e+08 2.01e+03 2.19e+01 -3.8 1.81e+06 - 1.20e-01 1.00e+00h 1\n", + " 49 -1.0426992e+08 2.91e+02 3.40e-01 -3.8 6.45e+04 -13.1 1.00e+00 9.64e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50 -1.0427006e+08 2.52e+02 4.03e+02 -3.8 6.79e+06 - 5.54e-03 2.58e-01h 1\n", + " 51 -1.0427055e+08 2.93e+02 3.98e+02 -3.8 3.24e+06 - 1.33e-01 1.93e-02h 1\n", + " 52 -1.0427009e+08 1.02e+02 1.15e+05 -3.8 2.79e+04 - 7.85e-04 1.00e+00f 1\n", + " 53 -1.0427045e+08 9.18e+01 7.72e+04 -3.8 4.68e+04 -12.6 1.00e+00 3.29e-01h 2\n", + " 54 -1.0427082e+08 9.84e+01 6.22e+04 -3.8 8.09e+04 -13.1 1.00e+00 1.92e-01h 2\n", + " 55 -1.0427081e+08 7.24e-01 1.18e+00 -3.8 7.63e+04 - 1.00e+00 1.00e+00h 1\n", + " 56 -1.0427115e+08 2.08e+01 2.49e+02 -3.8 3.14e+04 -12.7 1.00e+00 4.68e-01h 2\n", + " 57 -1.0427108e+08 6.33e-01 6.20e+00 -3.8 1.65e+04 - 1.00e+00 1.00e+00h 1\n", + " 58 -1.0427122e+08 3.69e+00 9.97e+02 -3.8 1.26e+04 -12.3 1.00e+00 4.66e-01h 2\n", + " 59 -1.0427122e+08 5.22e-05 1.89e-01 -3.8 1.65e+03 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60 -1.0428563e+08 3.80e+04 2.56e+04 -3.8 3.34e+06 - 7.06e-02 1.80e-01f 1\n", + " 61 -1.0428562e+08 3.78e+04 2.55e+04 -3.8 4.32e+05 - 2.18e-02 5.77e-03h 1\n", + " 62 -1.0428017e+08 3.77e+04 2.54e+04 -3.8 1.25e+07 -12.7 7.48e-05 2.34e-03h 9\n", + " 63 -1.0427440e+08 3.74e+04 2.52e+04 -3.8 3.76e+06 -12.3 5.74e-03 7.81e-03h 8\n", + " 64 -1.0427481e+08 3.74e+04 2.52e+04 -3.8 4.44e+05 -9.2 2.60e-01 1.25e-03h 1\n", + " 65 -1.0427459e+08 3.69e+04 2.49e+04 -3.8 4.18e+05 -9.7 3.22e-03 1.13e-02h 1\n", + " 66 -1.0427441e+08 3.69e+04 2.49e+04 -3.8 7.62e+08 -10.1 6.54e-09 7.13e-08f 11\n", + " 67 -1.0427290e+08 3.69e+04 2.49e+04 -3.8 8.98e+05 -9.7 1.79e-03 4.88e-04h 12\n", + " 68 -1.0427211e+08 3.69e+04 2.49e+04 -3.8 7.85e+05 -9.3 1.13e-03 4.88e-04h 12\n", + " 69 -1.0427200e+08 3.69e+04 2.49e+04 -3.8 1.16e+06 -9.8 2.41e-03 2.60e-05h 16\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70 -1.0427193e+08 3.69e+04 2.49e+04 -3.8 4.05e+05 -9.3 2.02e-01 2.35e-04h 5\n", + " 71 -1.0426925e+08 3.69e+04 2.49e+04 -3.8 1.03e+06 -9.8 6.63e-04 6.63e-04s 22\n", + " 72 -1.0425036e+08 3.57e+04 2.41e+04 -3.8 3.87e+05 -9.4 3.17e-02 3.17e-02s 22\n", + " 73 -1.0424520e+08 3.57e+04 2.41e+04 -3.8 1.58e+06 -9.9 9.56e-04 9.56e-04s 22\n", + " 74 -1.0421332e+08 3.51e+04 2.37e+04 -3.8 7.70e+05 -9.4 1.52e-02 1.52e-02s 22\n", + " 75 -1.0409397e+08 3.47e+04 2.34e+04 -3.8 2.08e+06 -9.9 1.36e-02 1.36e-02s 22\n", + " 76 -1.0387838e+08 2.73e+04 1.81e+04 -3.8 3.89e+05 -9.5 2.45e-01 2.45e-01s 22\n", + " 77 -1.0368499e+08 2.52e+04 1.67e+04 -3.8 5.49e+05 -10.0 8.21e-02 8.21e-02s 22\n", + " 78 -1.0298419e+08 2.17e+04 1.42e+04 -3.8 8.63e+05 -10.4 1.56e-01 1.56e-01s 22\n", + " 79 -1.0163132e+08 1.11e+04 6.55e+03 -3.8 5.27e+05 -10.9 6.20e-01 6.20e-01s 22\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80 -1.0194825e+08 1.09e+03 5.66e+02 -3.8 8.31e+04 -11.4 9.54e-01 9.54e-01s 22\n", + " 81 -1.0310109e+08 8.15e+02 4.00e+02 -3.8 5.53e+05 -11.9 2.90e-01 2.90e-01s 22\n", + " 82r-1.0310109e+08 8.15e+02 1.00e+03 -1.6 0.00e+00 -12.4 0.00e+00 0.00e+00R 1\n", + " 83r-1.0310498e+08 2.20e+02 3.18e+03 -1.6 1.50e+03 -4.0 2.25e-03 9.91e-04f 1\n", + " 84r-1.0303151e+08 8.00e+01 3.93e+03 -1.6 8.93e+06 - 3.97e-03 2.67e-03f 1\n", + " 85r-1.0297296e+08 3.79e+01 4.49e+03 -1.6 2.18e+06 - 9.30e-03 7.81e-03f 1\n", + " 86r-1.0295114e+08 8.32e+01 6.01e+03 -1.6 1.88e+06 - 2.57e-02 1.93e-02f 1\n", + " 87r-1.0295645e+08 6.88e+02 7.54e+03 -1.6 1.99e+06 - 6.81e-02 5.54e-02f 1\n", + " 88r-1.0295646e+08 5.58e+02 2.74e+04 -1.6 1.22e+02 -4.5 4.65e-01 1.86e-01f 1\n", + " 89r-1.0253465e+08 4.33e+02 1.34e+04 -1.6 4.11e+05 - 9.66e-01 2.98e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r-1.0417196e+08 5.86e+02 1.34e+04 -1.6 6.16e+06 - 3.39e-01 8.07e-02f 1\n", + " 91r-1.0366409e+08 6.25e+02 2.53e+03 -1.6 1.19e+05 - 2.93e-01 1.00e+00f 1\n", + " 92r-1.0364727e+08 2.09e+02 3.79e+02 -1.6 5.53e+01 -5.0 1.00e+00 6.66e-01h 1\n", + " 93r-1.0365950e+08 8.11e-03 1.47e+00 -1.6 6.58e+01 -5.4 1.00e+00 1.00e+00f 1\n", + " 94r-1.0367534e+08 2.57e-01 2.93e+03 -2.4 2.27e+02 -5.9 1.00e+00 8.08e-01f 1\n", + " 95r-1.0369165e+08 1.08e-01 3.47e+03 -2.4 2.04e+02 -6.4 1.00e+00 6.02e-01f 1\n", + " 96r-1.0369511e+08 2.28e-03 3.84e+00 -2.4 4.36e+01 -6.9 1.00e+00 1.00e+00f 1\n", + " 97r-1.0369311e+08 1.00e+03 1.22e+02 -2.4 1.53e+05 - 7.06e-01 1.00e+00f 1\n", + " 98r-1.0369133e+08 5.34e-02 6.47e-02 -2.4 6.89e+01 -7.3 1.00e+00 1.00e+00h 1\n", + " 99r-1.0364795e+08 1.01e+02 3.37e+02 -3.6 3.26e+04 - 6.54e-01 7.41e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r-1.0309823e+08 3.06e+01 6.46e+02 -3.6 1.67e+05 - 9.13e-01 9.87e-01f 1\n", + " 101r-1.0314314e+08 3.32e-01 6.34e+00 -3.6 1.21e+04 - 1.00e+00 1.00e+00f 1\n", + " 102r-1.0314312e+08 2.74e-05 1.09e-02 -3.6 3.60e+00 -7.8 1.00e+00 1.00e+00h 1\n", + " 103 -1.0319578e+08 9.61e-05 4.23e+01 -3.8 8.11e+03 - 9.97e-01 1.00e+00F 1\n", + " 104 -1.0413984e+08 4.94e+00 1.28e+03 -3.8 1.56e+06 - 8.31e-01 1.60e-01f 1\n", + " 105 -1.0414099e+08 4.85e+00 1.30e+03 -3.8 4.79e+04 - 1.33e-01 1.69e-02h 1\n", + " 106 -1.0417962e+08 1.56e+01 1.28e+03 -3.8 8.29e+06 - 9.95e-04 1.31e-02f 1\n", + " 107 -1.0415007e+08 1.55e+01 1.39e+01 -3.8 9.94e+04 - 9.52e-01 1.00e+00h 1\n", + " 108 -1.0417530e+08 2.20e+02 1.98e-01 -3.8 6.87e+04 - 9.90e-01 9.64e-01h 1\n", + " 109 -1.0428156e+08 1.32e+04 8.97e+01 -3.8 3.02e+06 - 7.12e-01 1.63e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110 -1.0426214e+08 2.88e+02 4.67e+01 -3.8 2.97e+05 - 5.07e-01 1.00e+00h 1\n", + " 111 -1.0426904e+08 1.71e+03 4.37e+01 -3.8 9.53e+06 - 4.40e-02 1.74e-01H 1\n", + " 112 -1.0427745e+08 1.25e+03 2.84e+00 -3.8 1.36e+06 - 9.80e-01 5.51e-01h 1\n", + " 113 -1.0427831e+08 4.62e+02 1.37e-03 -3.8 6.34e+05 - 1.00e+00 1.00e+00h 1\n", + " 114 -1.0427838e+08 1.66e+00 5.16e-06 -3.8 1.36e+04 - 1.00e+00 1.00e+00h 1\n", + " 115 -1.0427881e+08 2.67e+00 2.14e+02 -5.7 8.92e+04 - 9.86e-01 1.00e+00h 1\n", + " 116 -1.0427883e+08 1.12e-01 1.14e-03 -5.7 1.75e+04 - 1.00e+00 9.65e-01h 1\n", + " 117 -1.0427883e+08 2.06e-05 1.37e-08 -5.7 9.08e+02 - 1.00e+00 1.00e+00f 1\n", + " 118 -1.0427884e+08 5.70e-04 5.09e-06 -8.6 1.48e+03 - 1.00e+00 1.00e+00h 1\n", + " 119 -1.0427884e+08 3.73e-09 2.76e-13 -8.6 7.19e-01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120 -1.0427884e+08 1.86e-09 9.31e-12 -10.9 1.99e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 120\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -1.6119507851267775e+02 -1.0427883997848789e+08\n", + "Dual infeasibility......: 9.3067037146559845e-12 6.0206073060194729e-06\n", + "Constraint violation....: 1.0913936421275139e-10 1.8626451492309570e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 1.4067955341264719e-11 9.1007124869564871e-06\n", + "Overall NLP error.......: 1.0913936421275139e-10 9.1007124869564871e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 255\n", + "Number of objective gradient evaluations = 101\n", + "Number of equality constraint evaluations = 255\n", + "Number of inequality constraint evaluations = 255\n", + "Number of equality constraint Jacobian evaluations = 121\n", + "Number of inequality constraint Jacobian evaluations = 121\n", + "Number of Lagrangian Hessian evaluations = 120\n", + "Total seconds in IPOPT = 0.174\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 96\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 190 keys\n", + "that are not Var, Constraint, Objective, or the model. Skipping.\n", + "Ipopt 3.14.20: tol=1e-06\n", + "max_iter=200\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2025. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.14.20, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1236\n", + "Number of nonzeros in inequality constraint Jacobian.: 10\n", + "Number of nonzeros in Lagrangian Hessian.............: 779\n", + "\n", + "Total number of variables............................: 410\n", + " variables with only lower bounds: 49\n", + " variables with lower and upper bounds: 337\n", + " variables with only upper bounds: 1\n", + "Total number of equality constraints.................: 405\n", + "Total number of inequality constraints...............: 10\n", + " inequality constraints with only lower bounds: 5\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 5\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -1.0301714e+08 2.98e+05 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 -1.0365412e+08 1.32e+05 4.21e+01 -1.0 8.57e+04 - 8.59e-01 5.52e-01h 1\n", + " 2 -1.0410108e+08 5.26e+04 7.56e+03 -1.0 5.09e+04 - 9.61e-01 5.97e-01h 1\n", + " 3 -1.0413437e+08 2.06e+04 2.27e+02 -1.0 2.41e+04 - 9.37e-01 6.07e-01h 1\n", + " 4 -1.0424131e+08 1.93e+02 5.00e+03 -1.0 1.94e+05 - 9.87e-01 9.90e-01h 1\n", + " 5 -1.0420077e+08 9.43e+00 3.43e+03 -1.0 1.40e+05 - 9.11e-01 9.91e-01h 1\n", + " 6 -1.0416592e+08 2.19e+01 9.98e+05 -1.0 7.17e+05 - 7.26e-01 1.56e-02f 7\n", + " 7 -1.0366377e+08 9.17e+01 5.74e+05 -1.0 4.94e+05 - 5.51e-01 1.00e+00H 1\n", + " 8 -1.0363147e+08 9.84e+01 7.49e+06 -1.0 9.50e+05 - 9.90e-01 1.56e-02f 7\n", + " 9 -1.0252180e+08 7.86e+02 3.75e+04 -1.0 1.53e+06 - 7.68e-01 1.00e+00F 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 -1.0190033e+08 6.00e+00 1.87e+03 -1.0 2.37e+05 - 1.00e+00 1.00e+00H 1\n", + " 11 -1.0201665e+08 1.13e+01 8.51e+01 -1.0 1.34e+05 - 1.00e+00 1.00e+00H 1\n", + " 12 -1.0416792e+08 1.89e+04 2.50e+06 -2.5 1.28e+06 - 3.10e-01 5.67e-01f 1\n", + " 13 -1.0432990e+08 7.37e+04 1.94e+05 -2.5 1.61e+06 - 8.21e-01 6.69e-01h 1\n", + " 14 -1.0425973e+08 1.27e+02 1.47e+03 -2.5 4.32e+04 - 1.00e+00 1.00e+00h 1\n", + " 15 -1.0426575e+08 1.07e+01 1.87e-01 -2.5 5.16e+04 - 1.00e+00 1.00e+00h 1\n", + " 16 -1.0427763e+08 2.48e+01 2.62e+01 -3.8 6.19e+04 - 1.00e+00 1.00e+00h 1\n", + " 17 -1.0427797e+08 9.99e+01 2.44e-03 -3.8 3.85e+05 - 1.00e+00 1.00e+00h 1\n", + " 18 -1.0427790e+08 1.94e+00 1.79e-05 -3.8 5.18e+04 - 1.00e+00 1.00e+00h 1\n", + " 19 -1.0427873e+08 8.25e+00 5.26e+02 -5.7 1.32e+05 - 9.65e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 -1.0427883e+08 1.02e+00 6.20e-03 -5.7 6.34e+04 - 1.00e+00 9.13e-01h 1\n", + " 21 -1.0427883e+08 2.22e-03 7.11e-08 -5.7 2.00e+03 - 1.00e+00 1.00e+00f 1\n", + " 22 -1.0427884e+08 2.66e-03 1.10e-05 -8.6 3.26e+03 - 1.00e+00 1.00e+00h 1\n", + " 23 -1.0427884e+08 1.16e-08 1.87e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", + " 24 -1.0427884e+08 4.19e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 24\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: -7.4466968713582887e+01 -1.0427883997850095e+08\n", + "Dual infeasibility......: 2.0257749632681967e-11 2.8367673194755198e-05\n", + "Constraint violation....: 1.3824319466948509e-10 4.1909515857696533e-09\n", + "Variable bound violation: 5.1270817493787035e-06 5.1270817493787035e-06\n", + "Complementarity.........: 6.5249453183278187e-12 9.1371213367822650e-06\n", + "Overall NLP error.......: 1.3824319466948509e-10 2.8367673194755198e-05\n", + "\n", + "\n", + "Number of objective function evaluations = 52\n", + "Number of objective gradient evaluations = 25\n", + "Number of equality constraint evaluations = 52\n", + "Number of inequality constraint evaluations = 52\n", + "Number of equality constraint Jacobian evaluations = 25\n", + "Number of inequality constraint Jacobian evaluations = 25\n", + "Number of Lagrangian Hessian evaluations = 24\n", + "Total seconds in IPOPT = 0.026\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "Optimal solution process results:\n", + "\n", + "\n", + "Extent of reaction: 311.3069854950048\n", + "Stoichiometry of each component normalized by the extent:\n", + "CH4 : -0.0\n", + "H2 : -2.0\n", + "CH3OH : 1.0\n", + "CO : -1.0\n", + "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", + "\n", + "Reaction conversion: 0.8500000099996615\n", + "Reactor duty (MW): -59.34022107299101\n", + "Duty from Reaction (MW)): 28.216865165267237\n", + "Compressor work (MW): -4.7980486241206324e-24\n", + "Turbine work (MW): -2.491301208383993\n", + "Feed Mixer outlet temperature (C)): 20.051714213753485\n", + "Recycle Mixer outlet temperature (C)): 41.54321437801826\n", + "Feed Compressor outlet temperature (C)): 41.54321437801826\n", + "Feed Compressor outlet pressure (Pa)): 5100000.0\n", + "Heater outlet temperature (C)): 215.0\n", + "Reactor outlet temperature (C)): 231.85000478422364\n", + "Turbine outlet temperature (C)): 141.50037862882186\n", + "Turbine outlet pressure (Pa)): 1487177.2483574806\n", + "Cooler outlet temperature (C)): 52.56999699077659\n", + "Flash outlet temperature (C)): 134.0\n", + "Purge percentage (amount of vapor vented to exhaust): 9.999999000026644 %\n", + "Methanol recovery(%): 92.05882105498134\n", + "annualized capital cost ($/year) = 259559.90821288814\n", + "operating cost ($/year) = 525130020.70956033\n", + "sales ($/year) = 140033684437.28268\n", + "raw materials cost ($/year) = 35229454878.16397\n", + "revenue (1000$/year)= 104278839.97850095\n", + "\n", + "\n", + "====================================================================================\n", + "Unit : fs.H2 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 637.20\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000e-06\n", + " Total Mole Fraction H2 dimensionless 1.0000\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -142.40\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CO Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Outlet \n", + " Total Molar Flowrate mole / second 316.80\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", + " Total Mole Fraction CO dimensionless 1.0000\n", + " Total Mole Fraction H2 dimensionless 1.0000e-06\n", + " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", + " Molar Enthalpy joule / mole -1.1068e+05\n", + " Pressure pascal 3.0000e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.EXHAUST Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 22.743\n", + " Total Mole Fraction CH4 dimensionless 4.1946e-05\n", + " Total Mole Fraction CO dimensionless 0.24155\n", + " Total Mole Fraction H2 dimensionless 0.64134\n", + " Total Mole Fraction CH3OH dimensionless 0.11706\n", + " Molar Enthalpy joule / mole -47286.\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n", + "\n", + "====================================================================================\n", + "Unit : fs.CH3OH Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet \n", + " Total Molar Flowrate mole / second 308.65\n", + " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", + " Total Mole Fraction CO dimensionless 1.0000e-08\n", + " Total Mole Fraction H2 dimensionless 1.0000e-08\n", + " Total Mole Fraction CH3OH dimensionless 1.0000\n", + " Molar Enthalpy joule / mole -2.3792e+05\n", + " Pressure pascal 7.4845e+06\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "# Set up Optimization Problem (Maximize Revenue)\n", + "# keep process pre-reaction fixed and unfix some post-process specs\n", + "m.fs.R101.conversion.unfix()\n", + "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", + "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", + "m.fs.R101.outlet_temp.deactivate()\n", + "m.fs.R101.outlet_t_lb = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", + ")\n", + "m.fs.R101.outlet_t_ub = Constraint(\n", + " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", + ")\n", + "\n", + "# Optimize turbine work (or delta P)\n", + "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", + "m.fs.T101.outlet_p_lb = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", + ")\n", + "m.fs.T101.outlet_p_ub = Constraint(\n", + " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", + ")\n", + "\n", + "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", + "m.fs.H102.outlet_temp.deactivate()\n", + "m.fs.H102.outlet_t_lb = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", + " >= 407.15 * 0.8 * pyunits.K\n", + ")\n", + "m.fs.H102.outlet_t_ub = Constraint(\n", + " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", + ")\n", + "\n", + "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", + "\n", + "m.fs.F101.isothermal = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", + " == m.fs.F101.control_volume.properties_in[0].temperature\n", + ")\n", + "\n", + "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", + "m.fs.S101.split_fraction_lb = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", + ") # min 10% purge\n", + "m.fs.S101.split_fraction_ub = Constraint(\n", + " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", + ") # max 50% purge\n", + "\n", + "print()\n", + "print(\"Solving optimization problem...\")\n", + "\n", + "# Pass 1: smoothed VLE transition\n", + "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", + "\n", + "\n", + "solver.options[\"max_iter\"] = 200\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "# Pass 2: restore default smoothness\n", + "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", + "\n", + "opt_res = solver.solve(m, tee=True)\n", + "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", + "\n", + "print(\"Optimal solution process results:\")\n", + "report(m)" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: tol=1e-06\n", - "max_iter=100\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, recycling methanol and gases from the flash vapor achieves much greater methanol production, and process cost increases are small compared to the increase in revenue. Note that the reaction conversion and flash inlet temperature did not change, and we obtain the same percentage methanol recovery. We can see in the stream tables that far more of the inlet material exits as methanol than in the non-recycle process (note that we do not have a mole balance due to the reaction stoichiometry). The results show a slight increase in equipment and operating costs from increased throughput on each unit." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2026. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 1236\n", - "Number of nonzeros in inequality constraint Jacobian.: 10\n", - "Number of nonzeros in Lagrangian Hessian.............: 779\n", - "\n", - "Total number of variables............................: 410\n", - " variables with only lower bounds: 49\n", - " variables with lower and upper bounds: 337\n", - " variables with only upper bounds: 1\n", - "Total number of equality constraints.................: 405\n", - "Total number of inequality constraints...............: 10\n", - " inequality constraints with only lower bounds: 5\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 5\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 -1.0301714e+08 2.98e+05 1.00e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 -1.0365412e+08 1.32e+05 4.21e+01 -1.0 8.57e+04 - 8.59e-01 5.52e-01h 1\n", - " 2 -1.0410108e+08 5.26e+04 7.56e+03 -1.0 5.09e+04 - 9.61e-01 5.97e-01h 1\n", - " 3 -1.0413437e+08 2.06e+04 2.27e+02 -1.0 2.41e+04 - 9.37e-01 6.07e-01h 1\n", - " 4 -1.0424131e+08 1.93e+02 5.00e+03 -1.0 1.94e+05 - 9.87e-01 9.90e-01h 1\n", - " 5 -1.0420077e+08 9.43e+00 3.43e+03 -1.0 1.40e+05 - 9.11e-01 9.91e-01h 1\n", - " 6 -1.0416592e+08 2.19e+01 9.98e+05 -1.0 7.17e+05 - 7.26e-01 1.56e-02f 7\n", - " 7 -1.0366377e+08 9.17e+01 5.74e+05 -1.0 4.94e+05 - 5.51e-01 1.00e+00H 1\n", - " 8 -1.0363147e+08 9.84e+01 7.49e+06 -1.0 9.50e+05 - 9.90e-01 1.56e-02f 7\n", - " 9 -1.0252180e+08 7.86e+02 3.75e+04 -1.0 1.53e+06 - 7.68e-01 1.00e+00F 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 10 -1.0190033e+08 6.00e+00 1.87e+03 -1.0 2.37e+05 - 1.00e+00 1.00e+00H 1\n", - " 11 -1.0201665e+08 1.13e+01 8.51e+01 -1.0 1.34e+05 - 1.00e+00 1.00e+00H 1\n", - " 12 -1.0416792e+08 1.89e+04 2.50e+06 -2.5 1.28e+06 - 3.10e-01 5.67e-01f 1\n", - " 13 -1.0432990e+08 7.37e+04 1.94e+05 -2.5 1.61e+06 - 8.21e-01 6.69e-01h 1\n", - " 14 -1.0425973e+08 1.27e+02 1.47e+03 -2.5 4.32e+04 - 1.00e+00 1.00e+00h 1\n", - " 15 -1.0426575e+08 1.07e+01 1.87e-01 -2.5 5.16e+04 - 1.00e+00 1.00e+00h 1\n", - " 16 -1.0427763e+08 2.48e+01 2.62e+01 -3.8 6.19e+04 - 1.00e+00 1.00e+00h 1\n", - " 17 -1.0427797e+08 9.99e+01 2.44e-03 -3.8 3.85e+05 - 1.00e+00 1.00e+00h 1\n", - " 18 -1.0427790e+08 1.94e+00 1.79e-05 -3.8 5.18e+04 - 1.00e+00 1.00e+00h 1\n", - " 19 -1.0427873e+08 8.25e+00 5.26e+02 -5.7 1.32e+05 - 9.65e-01 1.00e+00h 1\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 20 -1.0427883e+08 1.02e+00 6.20e-03 -5.7 6.34e+04 - 1.00e+00 9.13e-01h 1\n", - " 21 -1.0427883e+08 2.22e-03 7.11e-08 -5.7 2.00e+03 - 1.00e+00 1.00e+00f 1\n", - " 22 -1.0427884e+08 2.66e-03 1.10e-05 -8.6 3.26e+03 - 1.00e+00 1.00e+00h 1\n", - " 23 -1.0427884e+08 1.16e-08 1.82e-13 -8.6 4.36e+00 - 1.00e+00 1.00e+00h 1\n", - " 24 -1.0427884e+08 3.14e-09 2.03e-11 -11.2 4.33e+00 - 1.00e+00 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 24\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: -7.4466968713582915e+01 -1.0427883997850099e+08\n", - "Dual infeasibility......: 2.0257749320973842e-11 2.8367672758258825e-05\n", - "Constraint violation....: 1.3824319466948509e-10 3.1432136893272400e-09\n", - "Complementarity.........: 6.5249453183277711e-12 9.1371213367821990e-06\n", - "Overall NLP error.......: 1.3824319466948509e-10 2.8367672758258825e-05\n", - "\n", - "\n", - "Number of objective function evaluations = 52\n", - "Number of objective gradient evaluations = 25\n", - "Number of equality constraint evaluations = 52\n", - "Number of inequality constraint evaluations = 52\n", - "Number of equality constraint Jacobian evaluations = 25\n", - "Number of inequality constraint Jacobian evaluations = 25\n", - "Number of Lagrangian Hessian evaluations = 24\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.027\n", - "Total CPU secs in NLP function evaluations = 0.002\n", - "\n", - "EXIT: Optimal Solution Found.\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 6. Summary\n", + "The present example demonstrates building, initializing and optimizing a methanol synthesis problem in IDAES. The imported scripts implement models from the IDAES pre-defined unit model library, the IDAES Property and Reaction Framework, targeted thermophysical properties for specific unit blocks, Pyomo's Sequential Decomposition methods, the IDAES Costing Framework for capital cost calculations, and integration of custom surrogate expressions for operating cost calculations. The methanol synthesis flowsheet methods may be imported into any external script, and users may build, initialize and optimize the entire model via the `main()` method in each flowsheet." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal solution process results:\n", - "\n", - "\n", - "Extent of reaction: 311.30698549500477\n", - "Stoichiometry of each component normalized by the extent:\n", - "CH4 : 0.0\n", - "H2 : -2.0\n", - "CH3OH : 1.0\n", - "CO : -1.0\n", - "These coefficients should follow 1*CO + 2*H2 => 1*CH3OH\n", - "\n", - "Reaction conversion: 0.8500000099996615\n", - "Reactor duty (MW): -59.340221072991014\n", - "Duty from Reaction (MW)): 28.216865165267233\n", - "Compressor work (MW): 1.2861669211016399e-24\n", - "Turbine work (MW): -2.4913012083840025\n", - "Feed Mixer outlet temperature (C)): 20.05171421375354\n", - "Recycle Mixer outlet temperature (C)): 41.54321437801775\n", - "Feed Compressor outlet temperature (C)): 41.54321437801792\n", - "Feed Compressor outlet pressure (Pa)): 5100000.0\n", - "Heater outlet temperature (C)): 215.0\n", - "Reactor outlet temperature (C)): 231.85000478422364\n", - "Turbine outlet temperature (C)): 141.50037862882152\n", - "Turbine outlet pressure (Pa)): 1487177.2483574792\n", - "Cooler outlet temperature (C)): 52.56999699077659\n", - "Flash outlet temperature (C)): 134.0\n", - "Purge percentage (amount of vapor vented to exhaust): 9.999999000026644 %\n", - "Methanol recovery(%): 92.05882105498138\n", - "annualized capital cost ($/year) = 259559.90821288762\n", - "operating cost ($/year) = 525130020.7095608\n", - "sales ($/year) = 140033684437.2827\n", - "raw materials cost ($/year) = 35229454878.16397\n", - "revenue (1000$/year)= 104278839.97850098\n", - "\n", - "\n", - "====================================================================================\n", - "Unit : fs.H2 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 637.20\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000e-06\n", - " Total Mole Fraction H2 dimensionless 1.0000\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -142.40\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CO Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Outlet \n", - " Total Molar Flowrate mole / second 316.80\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-06\n", - " Total Mole Fraction CO dimensionless 1.0000\n", - " Total Mole Fraction H2 dimensionless 1.0000e-06\n", - " Total Mole Fraction CH3OH dimensionless 1.0000e-06\n", - " Molar Enthalpy joule / mole -1.1068e+05\n", - " Pressure pascal 3.0000e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.EXHAUST Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 22.743\n", - " Total Mole Fraction CH4 dimensionless 4.1946e-05\n", - " Total Mole Fraction CO dimensionless 0.24155\n", - " Total Mole Fraction H2 dimensionless 0.64134\n", - " Total Mole Fraction CH3OH dimensionless 0.11706\n", - " Molar Enthalpy joule / mole -47286.\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n", - "\n", - "====================================================================================\n", - "Unit : fs.CH3OH Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet \n", - " Total Molar Flowrate mole / second 308.65\n", - " Total Mole Fraction CH4 dimensionless 1.0000e-08\n", - " Total Mole Fraction CO dimensionless 1.0000e-08\n", - " Total Mole Fraction H2 dimensionless 1.0000e-08\n", - " Total Mole Fraction CH3OH dimensionless 1.0000\n", - " Molar Enthalpy joule / mole -2.3792e+05\n", - " Pressure pascal 7.4845e+06\n", - "====================================================================================\n" - ] + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-20T21:01:13.775587500Z", + "start_time": "2026-02-20T21:01:13.771970400Z" + } + }, + "outputs": [], + "source": [] } - ], - "source": [ - "# Set up Optimization Problem (Maximize Revenue)\n", - "# keep process pre-reaction fixed and unfix some post-process specs\n", - "m.fs.R101.conversion.unfix()\n", - "m.fs.R101.conversion_lb = Constraint(expr=m.fs.R101.conversion >= 0.75)\n", - "m.fs.R101.conversion_ub = Constraint(expr=m.fs.R101.conversion <= 0.85)\n", - "m.fs.R101.outlet_temp.deactivate()\n", - "m.fs.R101.outlet_t_lb = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature >= 405 * pyunits.K\n", - ")\n", - "m.fs.R101.outlet_t_ub = Constraint(\n", - " expr=m.fs.R101.control_volume.properties_out[0.0].temperature <= 505 * pyunits.K\n", - ")\n", - "\n", - "# Optimize turbine work (or delta P)\n", - "m.fs.T101.deltaP.unfix() # optimize turbine work recovery/pressure drop\n", - "m.fs.T101.outlet_p_lb = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] >= 10e5 * pyunits.Pa\n", - ")\n", - "m.fs.T101.outlet_p_ub = Constraint(\n", - " expr=m.fs.T101.outlet.pressure[0] <= 51e5 * 0.8 * pyunits.Pa\n", - ")\n", - "\n", - "# Optimize Cooler outlet temperature - unfix cooler outlet temperature\n", - "m.fs.H102.outlet_temp.deactivate()\n", - "m.fs.H102.outlet_t_lb = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature\n", - " >= 407.15 * 0.8 * pyunits.K\n", - ")\n", - "m.fs.H102.outlet_t_ub = Constraint(\n", - " expr=m.fs.H102.control_volume.properties_out[0.0].temperature <= 480 * pyunits.K\n", - ")\n", - "\n", - "m.fs.F101.deltaP.unfix() # allow pressure change in streams\n", - "\n", - "m.fs.F101.isothermal = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].temperature\n", - " == m.fs.F101.control_volume.properties_in[0].temperature\n", - ")\n", - "\n", - "m.fs.S101.split_fraction[0, \"purge\"].unfix() # allow some gas recycle\n", - "m.fs.S101.split_fraction_lb = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] >= 0.10\n", - ") # min 10% purge\n", - "m.fs.S101.split_fraction_ub = Constraint(\n", - " expr=m.fs.S101.split_fraction[0, \"purge\"] <= 0.50\n", - ") # max 50% purge\n", - "\n", - "print()\n", - "print(\"Solving optimization problem...\")\n", - "\n", - "# Pass 1: smoothed VLE transition\n", - "eps_nominal = value(m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq)\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal * 2.5)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "# Pass 2: restore default smoothness\n", - "m.fs.F101.control_volume.properties_in[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "m.fs.F101.control_volume.properties_out[0.0].eps_2_Vap_Liq.set_value(eps_nominal)\n", - "\n", - "opt_res = solver.solve(m, tee=True)\n", - "assert opt_res.solver.termination_condition == TerminationCondition.optimal\n", - "\n", - "print(\"Optimal solution process results:\")\n", - "report(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, recycling methanol and gases from the flash vapor achieves much greater methanol production, and process cost increases are small compared to the increase in revenue. Note that the reaction conversion and flash inlet temperature did not change, and we obtain the same percentage methanol recovery. We can see in the stream tables that far more of the inlet material exits as methanol than in the non-recycle process (note that we do not have a mole balance due to the reaction stoichiometry). The results show a slight increase in equipment and operating costs from increased throughput on each unit." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 6. Summary\n", - "The present example demonstrates building, initializing and optimizing a methanol synthesis problem in IDAES. The imported scripts implement models from the IDAES pre-defined unit model library, the IDAES Property and Reaction Framework, targeted thermophysical properties for specific unit blocks, Pyomo's Sequential Decomposition methods, the IDAES Costing Framework for capital cost calculations, and integration of custom surrogate expressions for operating cost calculations. The methanol synthesis flowsheet methods may be imported into any external script, and users may build, initialize and optimize the entire model via the `main()` method in each flowsheet." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T21:01:25.622948300Z", - "start_time": "2026-02-20T21:01:25.619116Z" + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.11" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py index f65ff679..3fcf9278 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py @@ -1,6 +1,12 @@ -################################################################################# +#!/usr/bin/env python +# coding: utf-8 + +# In[1]: + + +############################################################################### # The Institute for the Design of Advanced Energy Systems Integrated Platform -# Framework (IDAES IP) was produced under the DOE Institute for the +# Framework (idaes IP) was produced under the DOE Institute for the # Design of Advanced Energy Systems (IDAES). # # Copyright (c) 2018-2026 by the software owners: The Regents of the @@ -9,7 +15,92 @@ # 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. -################################################################################# +############################################################################### + + +# +# # HDA Flowsheet Simulation and Optimization +# +# Author: Jaffer Ghouse
+# Maintainer: Tanner Polley
+# Updated: 2026-1-12 +# +# ## Learning outcomes +# +# +# - Construct a steady-state flowsheet using the IDAES unit model library +# - Connecting unit models in a flowsheet using Arcs +# - Using the SequentialDecomposition tool to initialize a flowsheet with recycle +# - Formulate and solve an optimization problem +# - Defining an objective function +# - Setting variable bounds +# - Adding additional constraints +# +# +# The general workflow of setting up an IDAES flowsheet is the following: +# +#      1 Importing Modules
+#      2 Building a Model
+#      3 Scaling the Model
+#      4 Specifying the Model
+#      5 Initializing the Model
+#      6 Solving the Model
+#      7 Analyzing and Visualizing the Results
+#      8 Optimizing the Model
+# +# We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises. +# +# +# ## Problem Statement +# +# Hydrodealkylation is a chemical reaction that often involves reacting +# an aromatic hydrocarbon in the presence of hydrogen gas to form a +# simpler aromatic hydrocarbon devoid of functional groups. In this +# example, toluene will be reacted with hydrogen gas at high temperatures +# to form benzene via the following reaction: +# +# **C6H5CH3 + H2 → C6H6 + CH4** +# +# +# This reaction is often accompanied by an equilibrium side reaction +# which forms diphenyl, which we will neglect for this example. +# +# This example is based on the 1967 AIChE Student Contest problem as +# present by Douglas, J.M., Chemical Design of Chemical Processes, 1988, +# McGraw-Hill. +# +# The flowsheet that we will be using for this module is shown below with the stream conditions. We will be processing toluene and hydrogen to produce at least 370 TPY of benzene. As shown in the flowsheet, there are two flash tanks, F101 to separate out the non-condensibles and F102 to further separate the benzene-toluene mixture to improve the benzene purity. Note that typically a distillation column is required to obtain high purity benzene but that is beyond the scope of this workshop. The non-condensibles separated out in F101 will be partially recycled back to M101 and the rest will be either purged or combusted for power generation.We will assume ideal gas for this flowsheet. The properties required for this module are available in the same directory: +# +# - hda_ideal_VLE.py +# - hda_reaction.py +# +# The state variables chosen for the property package are **flows of component by phase, temperature and pressure**. The components considered are: **toluene, hydrogen, benzene and methane**. Therefore, every stream has 8 flow variables, 1 temperature and 1 pressure variable. +# +# ![](HDA_flowsheet.png) +# +# + +# ## 1 Importing Modules +# ### 1.1 Importing required Pyomo and IDAES components +# +# +# To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo: +# - Constraint (to write constraints) +# - Var (to declare variables) +# - ConcreteModel (to create the concrete model object) +# - Expression (to evaluate values as a function of variables defined in the model) +# - Objective (to define an objective function for optimization) +# - SolverFactory (to solve the problem) +# - TransformationFactory (to apply certain transformations) +# - Arc (to connect two unit models) +# - SequentialDecomposition (to initialize the flowsheet in a sequential mode) +# +# For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/ +# + +# In[2]: + + from pyomo.environ import ( Constraint, Var, @@ -20,9 +111,26 @@ value, ) from pyomo.network import Arc + + +# From IDAES, we will be needing the FlowsheetBlock and the following unit models: +# - Feed +# - Mixer +# - Heater +# - StoichiometricReactor +# - **Flash** +# - Separator (splitter) +# - PressureChanger +# - Product + +# In[3]: + + from idaes.core import FlowsheetBlock -from idaes.core.util.model_statistics import degrees_of_freedom -from idaes.core.solvers import get_solver + + +# In[4]: + from idaes.models.unit_models import ( PressureChanger, @@ -32,277 +140,986 @@ StoichiometricReactor, Feed, Product, - Flash, ) + + +#
+# Inline Exercise: +# Now, import the remaining unit models highlighted in blue above and run the cell using `Shift+Enter` after typing in the code. +#
+# + +# In[5]: + + +# Todo: import flash model from idaes.models.unit_models + + +# In[6]: + + +# Todo: import flash model from idaes.models.unit_models +from idaes.models.unit_models import Flash + + +# We will also be needing some utility tools to put together the flowsheet and calculate the degrees of freedom. + +# In[7]: + + from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption +from idaes.core.util.model_statistics import degrees_of_freedom + +# Import idaes logger to set output levels +from idaes.core.solvers import get_solver + + +# ### 1.2 Importing required thermo and reaction package +# +# The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. +# +# The reaction package here is very simple as we will be using only a StochiometricReactor and the reaction package consists of the stochiometric coefficients for the reaction and the parameter for the heat of reaction. +# +# Let us import the following modules and they are in the same directory as this jupyter notebook: +#
    +#
  • hda_ideal_VLE as thermo_props
  • +#
  • hda_reaction as reaction_props
  • +#
+# + +# In[8]: + + from idaes.models.properties.modular_properties.base.generic_property import ( GenericParameterBlock, ) from idaes.models.properties.modular_properties.base.generic_reaction import ( GenericReactionParameterBlock, ) - from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config from idaes_examples.mod.hda.hda_reaction_modular import reaction_config -from idaes_examples.mod.hda.hda_flowsheet_extras import ( - manual_propagation, - automatic_propagation, - fix_inlet_states, + + +# ## 2 Constructing the Flowsheet +# +# We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block. + +# In[9]: + + +m = ConcreteModel() +m.fs = FlowsheetBlock(dynamic=False) + + +# We now need to add the property packages to the flowsheet. Unlike Module 1, where we only had a thermo property package, for this flowsheet we will also need to add a reaction property package. + +# In[10]: + + +m.fs.thermo_params = GenericParameterBlock(**thermo_config) +m.fs.reaction_params = GenericReactionParameterBlock( + property_package=m.fs.thermo_params, **reaction_config ) -if __name__ == "__main__": - m = ConcreteModel() - m.fs = FlowsheetBlock(dynamic=False) +# ### 2.1 Adding Unit Models +# +# Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`. - m.fs.thermo_params = GenericParameterBlock(**thermo_config) - m.fs.reaction_params = GenericReactionParameterBlock( - property_package=m.fs.thermo_params, **reaction_config - ) +# In[11]: - m.fs.I101 = Feed(property_package=m.fs.thermo_params) - m.fs.I102 = Feed(property_package=m.fs.thermo_params) - m.fs.M101 = Mixer( - property_package=m.fs.thermo_params, - num_inlets=3, - ) +m.fs.I101 = Feed(property_package=m.fs.thermo_params) +m.fs.I102 = Feed(property_package=m.fs.thermo_params) - m.fs.H101 = Heater( - property_package=m.fs.thermo_params, - has_pressure_change=False, - has_phase_equilibrium=True, - ) +m.fs.M101 = Mixer( + property_package=m.fs.thermo_params, + num_inlets=3, +) - m.fs.R101 = StoichiometricReactor( - property_package=m.fs.thermo_params, - reaction_package=m.fs.reaction_params, - has_heat_of_reaction=True, - has_heat_transfer=True, - has_pressure_change=False, - ) +m.fs.H101 = Heater( + property_package=m.fs.thermo_params, + has_pressure_change=False, + has_phase_equilibrium=True, +) - m.fs.F101 = Flash( - property_package=m.fs.thermo_params, - has_heat_transfer=True, - has_pressure_change=True, - ) - m.fs.S101 = Splitter( - property_package=m.fs.thermo_params, - ideal_separation=False, - outlet_list=["purge", "recycle"], - ) +#
+# Inline Exercise: +# Let us now add the StoichiometricReactor(assign the name R101) and pass the following arguments: +#
    +#
  • "property_package": m.fs.thermo_params
  • +#
  • "reaction_package": m.fs.reaction_params
  • +#
  • "has_heat_of_reaction": True
  • +#
  • "has_heat_transfer": True
  • +#
  • "has_pressure_change": False
  • +#
+#
- m.fs.C101 = PressureChanger( - property_package=m.fs.thermo_params, - compressor=True, - thermodynamic_assumption=ThermodynamicAssumption.isothermal, - ) +# In[12]: - m.fs.F102 = Flash( - property_package=m.fs.thermo_params, - has_heat_transfer=True, - has_pressure_change=True, - ) - m.fs.P101 = Product(property_package=m.fs.thermo_params) - m.fs.P102 = Product(property_package=m.fs.thermo_params) - m.fs.P103 = Product(property_package=m.fs.thermo_params) - - m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1) - m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2) - m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet) - m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet) - m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet) - m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet) - m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet) - m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet) - m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3) - m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet) - m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet) - m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet) - - TransformationFactory("network.expand_arcs").apply_to(m) - - m.fs.purity = Expression( - expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" +# Todo: Add reactor with the specifications above + + +# In[13]: + + +# Todo: Add reactor with the specifications above +m.fs.R101 = StoichiometricReactor( + property_package=m.fs.thermo_params, + reaction_package=m.fs.reaction_params, + has_heat_of_reaction=True, + has_heat_transfer=True, + has_pressure_change=False, +) + + +# Let us now add the Flash(assign the name F101) and pass the following arguments: +#
    +#
  • "property_package": m.fs.thermo_params
  • +#
  • "has_heat_transfer": True
  • +#
  • "has_pressure_change": False
  • +#
+ +# In[14]: + + +m.fs.F101 = Flash( + property_package=m.fs.thermo_params, + has_heat_transfer=True, + has_pressure_change=True, +) + + +# Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102). + +# In[15]: + + +m.fs.S101 = Splitter( + property_package=m.fs.thermo_params, + ideal_separation=False, + outlet_list=["purge", "recycle"], +) + + +m.fs.C101 = PressureChanger( + property_package=m.fs.thermo_params, + compressor=True, + thermodynamic_assumption=ThermodynamicAssumption.isothermal, +) + +m.fs.F102 = Flash( + property_package=m.fs.thermo_params, + has_heat_transfer=True, + has_pressure_change=True, +) + + +# Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency + +# In[16]: + + +m.fs.P101 = Product(property_package=m.fs.thermo_params) +m.fs.P102 = Product(property_package=m.fs.thermo_params) +m.fs.P103 = Product(property_package=m.fs.thermo_params) + + +# ### 2.2 Connecting Unit Models using Arcs +# +# We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101). + +# ![](HDA_flowsheet.png) + +# In[17]: + + +m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1) +m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2) +m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet) + + +#
+# Inline Exercise: +# Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. +#
+ +# In[18]: + + +# Todo: Connect the H101 outlet to R101 inlet + + +# In[19]: + + +# Todo: Connect the H101 outlet to R101 inlet +m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet) + + +# We will now be connecting the rest of the flowsheet as shown below. Notice how the outlet names are different for the flash tanks F101 and F102 as they have a vapor and a liquid outlet. + +# In[20]: + + +m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet) +m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet) +m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet) +m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet) +m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3) + + +# Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103) + +# In[21]: + + +m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet) +m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet) +m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet) + + +# We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows: + +# In[22]: + + +TransformationFactory("network.expand_arcs").apply_to(m) + + +# ### 2.3 Adding expressions to compute purity and operating costs +# +# In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html. +# +# For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. + +# Let us first add an Expression to compute the mole fraction of benzene in the `vap_outlet` of F102 which is our product stream. Please note that the var flow_mol_phase_comp has the index - [time, phase, component]. As this is a steady-state flowsheet, the time index by default is 0. The valid phases are ["Liq", "Vap"]. Similarly the valid component list is ["benzene", "toluene", "hydrogen", "methane"]. + +# In[23]: + + +m.fs.purity = Expression( + expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "benzene" + ] + / ( + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp["Vap", "benzene"] + + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "toluene" ] - / ( - m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" - ] - + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "toluene" - ] - ) ) +) - m.fs.cooling_cost = Expression( - expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0]) - ) - m.fs.heating_cost = Expression( - expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0] - ) +# Now, let us add an expression to compute the cooling cost assuming a cost of 0.212E-4 $/kW. Note that cooling utility is required for the reactor (R101) and the first flash (F101). - m.fs.operating_cost = Expression( - expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost)) - ) +# In[24]: + + +m.fs.cooling_cost = Expression( + expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0]) +) + + +# +# Now, let us add an expression to compute the heating cost assuming the utility cost as follows: +#
    +#
  • 2.2E-4 dollars/kW for H101
  • +#
  • 1.9E-4 dollars/kW for F102
  • +#
+# Note that the heat duty is in units of watt (J/s). + +# In[25]: + + +m.fs.heating_cost = Expression( + expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0] +) + + +# Let us now add an expression to compute the total operating cost per year which is basically the sum of the cooling and heating cost we defined above. + +# In[26]: + + +m.fs.operating_cost = Expression( + expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost)) +) + + +# ## 4 Specifying the Model +# ### 4.1 Fixing feed conditions +# +# Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. + +# In[27]: - assert degrees_of_freedom(m) == 29 - - tear_guesses = fix_inlet_states(m) - - m.fs.H101.outlet.temperature.fix(600) - - m.fs.R101.control_volume.conversion = Var(initialize=0.75, bounds=(0, 1)) - - m.fs.R101.conv_constraint = Constraint( - expr=m.fs.R101.control_volume.conversion - * ( - m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[ - "Vap", "toluene" - ] - ) - == ( - m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[ - "Vap", "toluene" - ] - - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "toluene" - ] - ) + +print(degrees_of_freedom(m)) + + +# In[28]: + + +# Check the degrees of freedom +assert degrees_of_freedom(m) == 29 + + +# We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note +# that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to +# help with convergence and initializing. We will be importing a function that will specify the inlet conditions for +# this example. + +# In[29]: + + +from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states + +tear_guesses = fix_inlet_states(m) + + +# ### 4.2 Fixing unit model specifications +# +# Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. + +# In[30]: + + +m.fs.H101.outlet.temperature.fix(600) + + +# For the StoichiometricReactor, we have to define the conversion in terms of toluene. This requires us to create a new variable for specifying the conversion and adding a Constraint that defines the conversion with respect to toluene. The second degree of freedom for the reactor is to define the heat duty. In this case, let us assume the reactor to be adiabatic i.e. Q = 0. + +# In[31]: + + +m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1)) + +m.fs.R101.conv_constraint = Constraint( + expr=m.fs.R101.conversion + * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp["Vap", "toluene"]) + == ( + m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp["Vap", "toluene"] + - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "toluene" + ] ) +) + +m.fs.R101.conversion.fix(0.75) +m.fs.R101.heat_duty.fix(0) + + +# The Flash conditions for F101 can be set as follows. + +# In[32]: + + +m.fs.F101.vap_outlet.temperature.fix(325.0) +m.fs.F101.deltaP.fix(0) + + +#
+# Inline Exercise: +# Set the conditions for Flash F102 to the following conditions: +#
    +#
  • T = 375 K
  • +#
  • deltaP = -200000
  • +#
+# +# Use Shift+Enter to run the cell once you have typed in your code. +#
+ +# In[33]: + + +# Todo: Set conditions for Flash F102 + + +# In[34]: + + +m.fs.F102.vap_outlet.temperature.fix(375) +m.fs.F102.deltaP.fix(-200000) + + +# Let us fix the purge split fraction to 20% and the outlet pressure of the compressor is set to 350000 Pa. + +# In[35]: + + +m.fs.S101.split_fraction[0, "purge"].fix(0.2) +m.fs.C101.outlet.pressure.fix(350000) + + +#
+# Inline Exercise: +# We have now defined all the feed conditions and the inputs required for the unit models. The system should now have 0 degrees of freedom i.e. should be a square problem. Please check that the degrees of freedom is 0. +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
+ +# In[36]: + - m.fs.R101.control_volume.conversion.fix(0.75) - m.fs.R101.heat_duty.fix(0.0) +# Todo: print the degrees of freedom - m.fs.F101.vap_outlet.temperature.fix(325.0) - m.fs.F101.deltaP.fix(0.0) - m.fs.F102.vap_outlet.temperature.fix(375) - m.fs.F102.deltaP.fix(-200000) +# In[37]: - m.fs.S101.split_fraction[0, "purge"].fix(0.2) - m.fs.C101.outlet.pressure.fix(350000) - # automatic_propagation(m, tear_guesses) - manual_propagation(m, tear_guesses) +print(degrees_of_freedom(m)) + + +# In[38]: + + +# Check the degrees of freedom +assert degrees_of_freedom(m) == 0 + + +# ## 5 Initializing the Model +# +# +# +# When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible. +# +# It is important to determine the tear stream for a flowsheet which will be demonstrated below. +# +# +# ![](HDA_tear_stream.png) +# +# Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or +# manually propagating through the flowsheet. The tear stream in this example will be the stream from the mixer to the heater since that is where the +# recycle stream first enters back into the main process. +# +# + +# First, we will highlight some helpful functions that are used in the initialization process. + +# In[39]: + + +def initialize_unit(unit): + from idaes.core.util.exceptions import InitializationError + import idaes.logger as idaeslog optarg = { - "nlp_scaling_method": "user-scaling", "OF_ma57_automatic_scaling": "yes", "max_iter": 1000, "tol": 1e-8, } - solver = get_solver("ipopt_v2", options=optarg) + try: + initializer = unit.default_initializer(solver_options=optarg) + initializer.initialize(unit, output_level=idaeslog.INFO_LOW) + except InitializationError: + solver = get_solver(solver_options=optarg) + solver.solve(unit) - # Solve the model - results = solver.solve(m, tee=False) - from pyomo.environ import TerminationCondition +# This first function will take any unit model and can either initialize the model with its respective default +# initializer, or use a generic solver and the solve the current state of the unit model. Often times a direct +# initialization method will fail while a solving method will converge so having the option for both is helpful. +# +# +# ### 5.1 Sequential Decomposition +# +# This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition - assert results.solver.termination_condition == TerminationCondition.optimal +# In[40]: - print("operating cost = $", value(m.fs.operating_cost)) - import pytest +def automatic_propagation(m, tear_guesses): - print("benzene purity = ", value(m.fs.purity)) + from pyomo.network import SequentialDecomposition - assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3) + seq = SequentialDecomposition() + seq.options.select_tear_method = "heuristic" + seq.options.tear_method = "Wegstein" + seq.options.iterLim = 5 - assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, abs=1e-3) - assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3) + # Using the SD tool + G = seq.create_graph(m) + heuristic_tear_set = seq.tear_set_arcs(G, method="heuristic") + order = seq.calculation_order(G) - m.fs.objective = Objective(expr=m.fs.operating_cost) + # Pass the tear_guess to the SD tool + seq.set_guesses_for(heuristic_tear_set[0].destination, tear_guesses) - m.fs.H101.outlet.temperature.unfix() - m.fs.R101.heat_duty.unfix() - m.fs.R101.outlet.temperature.fix(600) - m.fs.F101.vap_outlet.temperature.unfix() - m.fs.F102.vap_outlet.temperature.unfix() + print(f"Tear Stream starts at: {heuristic_tear_set[0].destination.name}") - m.fs.F102.deltaP.unfix() + for o in order: + print(o[0].name) - assert degrees_of_freedom(m) == 4 + seq.run(m, initialize_unit) - m.fs.H101.outlet.temperature[0].setlb(500) - m.fs.H101.outlet.temperature[0].setub(600) - m.fs.F101.vap_outlet.temperature[0].setlb(298.0) - m.fs.F101.vap_outlet.temperature[0].setub(450.0) - m.fs.F102.vap_outlet.temperature[0].setlb(298.0) - m.fs.F102.vap_outlet.temperature[0].setub(450.0) - m.fs.F102.vap_outlet.pressure[0].setlb(105000) - m.fs.F102.vap_outlet.pressure[0].setub(110000) +# We are now ready to initialize our flowsheet in a sequential mode. Note that we specifically set the iteration limit +# to be 5 as we are trying to use this tool only to get a good set of initial values such that IPOPT can then take over +# and solve this flowsheet for us. Uncomment this function call to run the automatic propagation method - m.fs.overhead_loss = Constraint( - expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" - ] - <= 0.20 - * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" - ] - ) +# In[41]: - m.fs.product_flow = Constraint( - expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" - ] - >= 0.15 - ) - m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80) +# automatic_propagation(m, tear_guesses) - results = solver.solve(m, tee=False) - # Check for solver solve status - from pyomo.environ import TerminationCondition +# ### 5.2 Manual Propagation Method +# +# This method uses a more direct approach to initialize the flowsheet, using the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly. +# Lets define the function that will help us manually propagate and step through the flowsheet - assert results.solver.termination_condition == TerminationCondition.optimal +# In[42]: - print("operating cost = $", value(m.fs.operating_cost)) - print() - print("Product flow rate and purity in F102") - m.fs.F102.report() +def manual_propagation(m, tear_guesses): + from idaes.core.util.initialization import propagate_state - print() - print("benzene purity = ", value(m.fs.purity)) + print(f"The DOF is {degrees_of_freedom(m)} initially") + m.fs.s03_expanded.deactivate() + print(f"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream") - print() - print("Overhead loss in F101") - m.fs.F101.report() + for k, v in tear_guesses.items(): + for k1, v1 in v.items(): + getattr(m.fs.s03.destination, k)[k1].fix(v1) - # - assert value(m.fs.operating_cost) == pytest.approx(312674.236, abs=1e-3) - assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3) + print(f"The DOF is {degrees_of_freedom(m)} after setting the tear stream") - print( - f"""Optimal Values: + optarg = { + "OF_ma57_automatic_scaling": "yes", + "max_iter": 300, + # "tol": 1e-10, + } - H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K + solver = get_solver(solver_options=optarg) - R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W + initialize_unit(m.fs.H101) # Initialize Heater + propagate_state(m.fs.s04) # Establish connection between Heater and Reactor + initialize_unit(m.fs.R101) # Initialize Reactor + propagate_state( + m.fs.s05 + ) # Establish connection between Reactor and First Flash Unit + initialize_unit(m.fs.F101) # Initialize First Flash Unit + propagate_state( + m.fs.s06 + ) # Establish connection between First Flash Unit and Splitter + propagate_state( + m.fs.s07 + ) # Establish connection between First Flash Unit and Second Flash Unit + initialize_unit(m.fs.S101) # Initialize Splitter + propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor + initialize_unit(m.fs.C101) # Initialize Compressor + propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer + initialize_unit(m.fs.I101) # Initialize Toluene Inlet + propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer + initialize_unit(m.fs.I102) # Initialize Hydrogen Inlet + propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer + initialize_unit(m.fs.M101) # Initialize Mixer + propagate_state(m.fs.s03) # Establish connection between Mixer and Heater + solver.solve(m.fs.F102) + propagate_state( + m.fs.s10 + ) # Establish connection between Second Flash Unit and Benzene Product + propagate_state( + m.fs.s11 + ) # Establish connection between Second Flash Unit and Toluene Product + propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product - F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K + optarg = { + "OF_ma57_automatic_scaling": "yes", + "max_iter": 300, + "tol": 1e-8, + } + solver = get_solver("ipopt_v2", options=optarg) + solver.solve(m, tee=False) - F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K - F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa - """ - ) + for k, v in tear_guesses.items(): + for k1, v1 in v.items(): + getattr(m.fs.H101.inlet, k)[k1].unfix() - assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3) - assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, abs=1e-3) - assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx( - 301.881, abs=1e-3 - ) - assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx( - 362.935, abs=1e-3 + m.fs.s03_expanded.activate() + print( + f"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream" ) - assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2) + + +# It will first show that the degrees of freedom is correctly at 0 before any streams are deactivated. Once the tear +# stream is deactivated though, the degrees of freedom will be 10. That means 10 variables will have to be defined with +# the tear guesses `tear_guesses`. Then each unit model can be initialized with our same helper function and then can +# propagate the corresponding connection to the following unit models. At the end, the whole flowsheet is solved, +# giving a much better chance for the recycle stream to be used correctly the flowsheet to converge. + +# In[43]: + + +manual_propagation(m, tear_guesses) + + +# ## 6 Solving the Model + +# We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html + +# In[44]: + + +optarg = { + "OF_ma57_automatic_scaling": "yes", + "max_iter": 300, + "tol": 1e-8, +} + + +#
+# Inline Exercise: +# Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following: +# +# solver = get_solver(solver_options=optarg)
+# results = solver.solve(m, tee=True) +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
+# + +# In[45]: + + +# Create the solver object + +# Solve the model + + +# In[46]: + + +# Create the solver object +solver = get_solver("ipopt_v2", options=optarg) + +# Solve the model +results = solver.solve(m, tee=True) + + +# In[47]: + + +# Check solver solve status +from pyomo.environ import TerminationCondition + +assert results.solver.termination_condition == TerminationCondition.optimal + + +# ## 7 Analyze the results +# +# +# + +# If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window. +# + +# In[48]: + + +# m.fs.visualize("HDA-Flowsheet") + + +# Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display. + +# In[49]: + + +m.fs.report() + + +# What is the total operating cost? + +# In[50]: + + +print("operating cost = $", value(m.fs.operating_cost)) + + +# In[51]: + + +import pytest + +assert value(m.fs.operating_cost) == pytest.approx(419008.28189, rel=1e-6) + + +# For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method. + +# In[52]: + + +m.fs.F102.report() + +print() +print("benzene purity = ", value(m.fs.purity)) + + +# In[53]: + + +assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3) +assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, abs=1e-3) +assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3) + + +# Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101. + +# In[54]: + + +from idaes.core.util.tables import ( + create_stream_table_dataframe, + stream_table_dataframe_to_string, +) + +st = create_stream_table_dataframe({"Reactor": m.fs.s05, "Light Gases": m.fs.s06}) +print(stream_table_dataframe_to_string(st)) + + +# ## 8 Optimization +# +# +# We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\%. However, we are losing around 42\% of benzene in F101 vapor outlet stream. +# +# Let us try to minimize this cost such that: +# - we are producing at least 0.15 mol/s of benzene in F102 vapor outlet i.e. our product stream +# - purity of benzene i.e. the mole fraction of benzene in F102 vapor outlet is at least 80% +# - restricting the benzene loss in F101 vapor outlet to less than 20% +# +# For this problem, our decision variables are as follows: +# - H101 outlet temperature +# - R101 cooling duty provided +# - F101 outlet temperature +# - F102 outlet temperature +# - F102 deltaP in the flash tank +# + +# Let us declare our objective function for this problem. + +# In[55]: + + +m.fs.objective = Objective(expr=m.fs.operating_cost) + + +# Now, we need to unfix the decision variables as we had solved a square problem (degrees of freedom = 0) until now. +# +# Because we are using a stoichiometric reactor, the reactor temperature has no effect on the reaction yield. Additionally, we are using the same cost for heat removal from both the reactor and flash units. Therefore, the optimization algorithm has no reason to prefer heat removal in one place or the other; the solution returned is not locally unique. To remove this indeterminancy and ensure that a consistent solution is returned, we fix the outlet temperature of the reactor. + +# In[56]: + + +m.fs.H101.outlet.temperature.unfix() +m.fs.R101.heat_duty.unfix() +m.fs.R101.outlet.temperature.fix(600) +m.fs.F101.vap_outlet.temperature.unfix() +m.fs.F102.vap_outlet.temperature.unfix() + + +#
+# Inline Exercise: +# Let us now unfix the remaining variable which is F102 pressure drop (F102.deltaP) +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
+# +# + +# In[57]: + + +# Todo: Unfix deltaP for F102 + + +# In[58]: + + +# Todo: Unfix deltaP for F102 +m.fs.F102.deltaP.unfix() + + +# In[59]: + + +assert degrees_of_freedom(m) == 4 + + +# Next, we need to set bounds on these decision variables to values shown below: +# +# - H101 outlet temperature [500, 600] K +# - F101 outlet temperature [298, 450] K +# - F102 outlet temperature [298, 450] K +# - F102 outlet pressure [105000, 110000] Pa +# +# Let us first set the variable bound for the H101 outlet temperature as shown below: + +# In[60]: + + +m.fs.H101.outlet.temperature[0].setlb(500) +m.fs.H101.outlet.temperature[0].setub(600) + + +#
+# Inline Exercise: +# Now, set the variable bound for the F101 outlet temperature. +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
+ +# In[61]: + + +# Todo: Set the bounds for flash 101 outlet temperature + + +# In[62]: + + +# Todo: Set the bounds for reactor outlet temperature +m.fs.F101.vap_outlet.temperature[0].setlb(298.0) +m.fs.F101.vap_outlet.temperature[0].setub(450.0) + + +# Let us fix the bounds for the rest of the decision variables. + +# In[63]: + + +m.fs.F102.vap_outlet.temperature[0].setlb(298.0) +m.fs.F102.vap_outlet.temperature[0].setub(450.0) +m.fs.F102.vap_outlet.pressure[0].setlb(105000) +m.fs.F102.vap_outlet.pressure[0].setub(110000) + + +# Now, the only things left to define are our constraints on overhead loss in F101, product flow rate and purity in F102. Let us first look at defining a constraint for the overhead loss in F101 where we are restricting the benzene leaving the vapor stream to less than 20 \% of the benzene available in the reactor outlet. + +# In[64]: + + +m.fs.overhead_loss = Constraint( + expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "benzene" + ] + <= 0.20 + * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp["Vap", "benzene"] +) + + +#
+# Inline Exercise: +# Now, add the constraint such that we are producing at least 0.15 mol/s of benzene in the product stream which is the vapor outlet of F102. Let us name this constraint as m.fs.product_flow. +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
+ +# In[65]: + + +# Todo: Add minimum product flow constraint + + +# In[66]: + + +# Todo: Add minimum product flow constraint +m.fs.product_flow = Constraint( + expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "benzene" + ] + >= 0.15 +) + + +# Let us add the final constraint on product purity or the mole fraction of benzene in the product stream such that it is at least greater than 80%. + +# In[67]: + + +m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80) + + +# +# We have now defined the optimization problem and we are now ready to solve this problem. +# +# +# + +# In[68]: + + +results = solver.solve(m, tee=False) + + +# In[69]: + + +# Check for solver solve status +from pyomo.environ import TerminationCondition + +assert results.solver.termination_condition == TerminationCondition.optimal + + +# ### 8.1 Optimization Results +# +# Display the results and product specifications + +# In[70]: + + +print("operating cost = $", value(m.fs.operating_cost)) + +print() +print("Product flow rate and purity in F102") + +m.fs.F102.report() + +print() +print("benzene purity = ", value(m.fs.purity)) + +print() +print("Overhead loss in F101") +m.fs.F101.report() + + +# In[71]: + + +assert value(m.fs.operating_cost) == pytest.approx(312674.236, rel=1e-4) +assert value(m.fs.purity) == pytest.approx(0.818827, rel=1e-4) + + +# Display optimal values for the decision variables + +# In[72]: + + +print( + f"""Optimal Values: + +H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K + +R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W + +F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K + +F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K +F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa +""" +) + + +# In[73]: + + +assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, rel=1e-4) +assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, rel=1e-4) +assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, rel=1e-4) +assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, rel=1e-4) +assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, rel=1e-4) + diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb index 6d60d8b3..e219ec93 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb @@ -1,1884 +1,1884 @@ { - "cells": [ - { - "cell_type": "code", - "metadata": { - "tags": [ - "header", - "hide-cell" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:42.610778Z", - "start_time": "2026-02-25T17:35:42.602689400Z" - } - }, - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (idaes IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ], - "outputs": [], - "execution_count": 1 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "# HDA Flowsheet Simulation and Optimization\n", - "\n", - "Author: Jaffer Ghouse
\n", - "Maintainer: Tanner Polley
\n", - "Updated: 2026-1-12\n", - "\n", - "## Learning outcomes\n", - "\n", - "\n", - "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", - "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Formulate and solve an optimization problem\n", - " - Defining an objective function\n", - " - Setting variable bounds\n", - " - Adding additional constraints\n", - "\n", - "\n", - "The general workflow of setting up an IDAES flowsheet is the following:\n", - "\n", - "     1 Importing Modules
\n", - "     2 Building a Model
\n", - "     3 Scaling the Model
\n", - "     4 Specifying the Model
\n", - "     5 Initializing the Model
\n", - "     6 Solving the Model
\n", - "     7 Analyzing and Visualizing the Results
\n", - "     8 Optimizing the Model
\n", - "\n", - "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", - "\n", - "\n", - "## Problem Statement\n", - "\n", - "Hydrodealkylation is a chemical reaction that often involves reacting\n", - "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", - "simpler aromatic hydrocarbon devoid of functional groups. In this\n", - "example, toluene will be reacted with hydrogen gas at high temperatures\n", - " to form benzene via the following reaction:\n", - "\n", - "**C6H5CH3 + H2 → C6H6 + CH4**\n", - "\n", - "\n", - "This reaction is often accompanied by an equilibrium side reaction\n", - "which forms diphenyl, which we will neglect for this example.\n", - "\n", - "This example is based on the 1967 AIChE Student Contest problem as\n", - "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", - "McGraw-Hill.\n", - "\n", - "The flowsheet that we will be using for this module is shown below with the stream conditions. We will be processing toluene and hydrogen to produce at least 370 TPY of benzene. As shown in the flowsheet, there are two flash tanks, F101 to separate out the non-condensibles and F102 to further separate the benzene-toluene mixture to improve the benzene purity. Note that typically a distillation column is required to obtain high purity benzene but that is beyond the scope of this workshop. The non-condensibles separated out in F101 will be partially recycled back to M101 and the rest will be either purged or combusted for power generation.We will assume ideal gas for this flowsheet. The properties required for this module are available in the same directory:\n", - "\n", - "- hda_ideal_VLE.py\n", - "- hda_reaction.py\n", - "\n", - "The state variables chosen for the property package are **flows of component by phase, temperature and pressure**. The components considered are: **toluene, hydrogen, benzene and methane**. Therefore, every stream has 8 flow variables, 1 temperature and 1 pressure variable. \n", - "\n", - "![](HDA_flowsheet.png)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1 Importing Modules\n", - "### 1.1 Importing required Pyomo and IDAES components\n", - "\n", - "\n", - "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", - "- Constraint (to write constraints)\n", - "- Var (to declare variables)\n", - "- ConcreteModel (to create the concrete model object)\n", - "- Expression (to evaluate values as a function of variables defined in the model)\n", - "- Objective (to define an objective function for optimization)\n", - "- SolverFactory (to solve the problem)\n", - "- TransformationFactory (to apply certain transformations)\n", - "- Arc (to connect two unit models)\n", - "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", - "\n", - "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:43.110992100Z", - "start_time": "2026-02-25T17:35:42.612282300Z" - } - }, - "source": [ - "from pyomo.environ import (\n", - " Constraint,\n", - " Var,\n", - " ConcreteModel,\n", - " Expression,\n", - " Objective,\n", - " TransformationFactory,\n", - " value,\n", - ")\n", - "from pyomo.network import Arc" - ], - "outputs": [], - "execution_count": 2 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", - "- Feed\n", - "- Mixer\n", - "- Heater\n", - "- StoichiometricReactor\n", - "- **Flash**\n", - "- Separator (splitter) \n", - "- PressureChanger\n", - "- Product" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:44.809057200Z", - "start_time": "2026-02-25T17:35:43.112495700Z" - } - }, - "source": "from idaes.core import FlowsheetBlock", - "outputs": [], - "execution_count": 3 - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:44.872356400Z", - "start_time": "2026-02-25T17:35:44.811121200Z" - } - }, - "source": [ - "from idaes.models.unit_models import (\n", - " PressureChanger,\n", - " Mixer,\n", - " Separator as Splitter,\n", - " Heater,\n", - " StoichiometricReactor,\n", - " Feed,\n", - " Product,\n", - ")" - ], - "outputs": [], - "execution_count": 4 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Now, import the remaining unit models highlighted in blue above and run the cell using `Shift+Enter` after typing in the code. \n", - "
\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:44.881281600Z", - "start_time": "2026-02-25T17:35:44.874866900Z" - } - }, - "source": [ - "# Todo: import flash model from idaes.models.unit_models\n", - "from idaes.models.unit_models import Flash" - ], - "outputs": [], - "execution_count": 5 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will also be needing some utility tools to put together the flowsheet and calculate the degrees of freedom. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:44.908324500Z", - "start_time": "2026-02-25T17:35:44.882301100Z" - } - }, - "source": [ - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "\n", - "# Import idaes logger to set output levels\n", - "from idaes.core.solvers import get_solver" - ], - "outputs": [], - "execution_count": 6 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.2 Importing required thermo and reaction package\n", - "\n", - "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", - "\n", - "The reaction package here is very simple as we will be using only a StochiometricReactor and the reaction package consists of the stochiometric coefficients for the reaction and the parameter for the heat of reaction. \n", - "\n", - "Let us import the following modules and they are in the same directory as this jupyter notebook:\n", - "
    \n", - "
  • hda_ideal_VLE as thermo_props
  • \n", - "
  • hda_reaction as reaction_props
  • \n", - "
\n", - "" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:44.965042100Z", - "start_time": "2026-02-25T17:35:44.911556300Z" - } - }, - "cell_type": "code", - "source": [ - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", - "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ], - "outputs": [], - "execution_count": 7 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2 Constructing the Flowsheet\n", - "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:44.974105600Z", - "start_time": "2026-02-25T17:35:44.966089100Z" - } - }, - "source": [ - "m = ConcreteModel()\n", - "m.fs = FlowsheetBlock(dynamic=False)" - ], - "outputs": [], - "execution_count": 8 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now need to add the property packages to the flowsheet. Unlike Module 1, where we only had a thermo property package, for this flowsheet we will also need to add a reaction property package. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.002864200Z", - "start_time": "2026-02-25T17:35:44.974611900Z" - } - }, - "source": [ - "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", - "m.fs.reaction_params = GenericReactionParameterBlock(\n", - " property_package=m.fs.thermo_params, **reaction_config\n", - ")" - ], - "outputs": [], - "execution_count": 9 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.1 Adding Unit Models\n", - "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.051674800Z", - "start_time": "2026-02-25T17:35:45.003876900Z" - } - }, - "source": [ - "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", - "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", - "\n", - "m.fs.M101 = Mixer(\n", - " property_package=m.fs.thermo_params,\n", - " num_inlets=3,\n", - ")\n", - "\n", - "m.fs.H101 = Heater(\n", - " property_package=m.fs.thermo_params,\n", - " has_pressure_change=False,\n", - " has_phase_equilibrium=True,\n", - ")" - ], - "outputs": [], - "execution_count": 10 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.131872900Z", - "start_time": "2026-02-25T17:35:45.054728300Z" - } - }, - "source": [ - "# Todo: Add reactor with the specifications above\n", - "m.fs.R101 = StoichiometricReactor(\n", - " property_package=m.fs.thermo_params,\n", - " reaction_package=m.fs.reaction_params,\n", - " has_heat_of_reaction=True,\n", - " has_heat_transfer=True,\n", - " has_pressure_change=False,\n", - ")" - ], - "outputs": [], - "execution_count": 11 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us now add the Flash(assign the name F101) and pass the following arguments:\n", - "
    \n", - "
  • \"property_package\": m.fs.thermo_params
  • \n", - "
  • \"has_heat_transfer\": True
  • \n", - "
  • \"has_pressure_change\": False
  • \n", - "
" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.155620400Z", - "start_time": "2026-02-25T17:35:45.134902300Z" - } - }, - "source": [ - "m.fs.F101 = Flash(\n", - " property_package=m.fs.thermo_params,\n", - " has_heat_transfer=True,\n", - " has_pressure_change=True,\n", - ")" - ], - "outputs": [], - "execution_count": 12 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.199739800Z", - "start_time": "2026-02-25T17:35:45.157648400Z" - } - }, - "source": [ - "m.fs.S101 = Splitter(\n", - " property_package=m.fs.thermo_params,\n", - " ideal_separation=False,\n", - " outlet_list=[\"purge\", \"recycle\"],\n", - ")\n", - "\n", - "\n", - "m.fs.C101 = PressureChanger(\n", - " property_package=m.fs.thermo_params,\n", - " compressor=True,\n", - " thermodynamic_assumption=ThermodynamicAssumption.isothermal,\n", - ")\n", - "\n", - "m.fs.F102 = Flash(\n", - " property_package=m.fs.thermo_params,\n", - " has_heat_transfer=True,\n", - " has_pressure_change=True,\n", - ")" - ], - "outputs": [], - "execution_count": 13 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.219524300Z", - "start_time": "2026-02-25T17:35:45.203730200Z" - } - }, - "source": [ - "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", - "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", - "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ], - "outputs": [], - "execution_count": 14 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.2 Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](HDA_flowsheet.png)" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.230688Z", - "start_time": "2026-02-25T17:35:45.221026400Z" - } - }, - "source": [ - "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", - "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ], - "outputs": [], - "execution_count": 15 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.239823900Z", - "start_time": "2026-02-25T17:35:45.233204900Z" - } - }, - "source": [ - "# Todo: Connect the H101 outlet to R101 inlet\n", - "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ], - "outputs": [], - "execution_count": 16 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now be connecting the rest of the flowsheet as shown below. Notice how the outlet names are different for the flash tanks F101 and F102 as they have a vapor and a liquid outlet. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.250523300Z", - "start_time": "2026-02-25T17:35:45.242242Z" - } - }, - "source": [ - "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", - "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", - "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", - "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ], - "outputs": [], - "execution_count": 17 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.261058100Z", - "start_time": "2026-02-25T17:35:45.252570Z" - } - }, - "source": [ - "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", - "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", - "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ], - "outputs": [], - "execution_count": 18 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows:" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.289533400Z", - "start_time": "2026-02-25T17:35:45.263101200Z" - } - }, - "source": [ - "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ], - "outputs": [], - "execution_count": 19 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.3 Adding expressions to compute purity and operating costs\n", - "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", - "\n", - "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us first add an Expression to compute the mole fraction of benzene in the `vap_outlet` of F102 which is our product stream. Please note that the var flow_mol_phase_comp has the index - [time, phase, component]. As this is a steady-state flowsheet, the time index by default is 0. The valid phases are [\"Liq\", \"Vap\"]. Similarly the valid component list is [\"benzene\", \"toluene\", \"hydrogen\", \"methane\"]." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.300309800Z", - "start_time": "2026-02-25T17:35:45.292167800Z" - } - }, - "source": [ - "m.fs.purity = Expression(\n", - " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"benzene\"\n", - " ]\n", - " / (\n", - " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", - " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"toluene\"\n", - " ]\n", - " )\n", - ")" - ], - "outputs": [], - "execution_count": 20 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let us add an expression to compute the cooling cost assuming a cost of 0.212E-4 $/kW. Note that cooling utility is required for the reactor (R101) and the first flash (F101). " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.309703500Z", - "start_time": "2026-02-25T17:35:45.303385800Z" - } - }, - "source": [ - "m.fs.cooling_cost = Expression(\n", - " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", - ")" - ], - "outputs": [], - "execution_count": 21 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Now, let us add an expression to compute the heating cost assuming the utility cost as follows:\n", - "
    \n", - "
  • 2.2E-4 dollars/kW for H101
  • \n", - "
  • 1.9E-4 dollars/kW for F102
  • \n", - "
\n", - "Note that the heat duty is in units of watt (J/s). " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.320965500Z", - "start_time": "2026-02-25T17:35:45.312333600Z" - } - }, - "source": [ - "m.fs.heating_cost = Expression(\n", - " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", - ")" - ], - "outputs": [], - "execution_count": 22 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us now add an expression to compute the total operating cost per year which is basically the sum of the cooling and heating cost we defined above. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.329622500Z", - "start_time": "2026-02-25T17:35:45.324028100Z" - } - }, - "source": [ - "m.fs.operating_cost = Expression(\n", - " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", - ")" - ], - "outputs": [], - "execution_count": 23 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4 Specifying the Model\n", - "### 4.1 Fixing feed conditions\n", - "\n", - "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.369170900Z", - "start_time": "2026-02-25T17:35:45.333072800Z" - } - }, - "source": [ - "print(degrees_of_freedom(m))" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "29\n" - ] - } - ], - "execution_count": 24 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note\n", - "that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to\n", - "help with convergence and initializing. We will be importing a function that will specify the inlet conditions for\n", - "this example." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.379924400Z", - "start_time": "2026-02-25T17:35:45.369170900Z" - } - }, - "source": [ - "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", - "\n", - "tear_guesses = fix_inlet_states(m)" - ], - "outputs": [], - "execution_count": 25 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4.2 Fixing unit model specifications\n", - "\n", - "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.476126100Z", - "start_time": "2026-02-25T17:35:45.382210200Z" - } - }, - "source": [ - "m.fs.H101.outlet.temperature.fix(600)" - ], - "outputs": [], - "execution_count": 26 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For the StoichiometricReactor, we have to define the conversion in terms of toluene. This requires us to create a new variable for specifying the conversion and adding a Constraint that defines the conversion with respect to toluene. The second degree of freedom for the reactor is to define the heat duty. In this case, let us assume the reactor to be adiabatic i.e. Q = 0. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.487469500Z", - "start_time": "2026-02-25T17:35:45.478353100Z" - } - }, - "source": [ - "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", - "\n", - "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion\n", - " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", - " == (\n", - " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", - " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"toluene\"\n", - " ]\n", - " )\n", - ")\n", - "\n", - "m.fs.R101.conversion.fix(0.75)\n", - "m.fs.R101.heat_duty.fix(0)" - ], - "outputs": [], - "execution_count": 27 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The Flash conditions for F101 can be set as follows. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.494918400Z", - "start_time": "2026-02-25T17:35:45.487469500Z" - } - }, - "source": [ - "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", - "m.fs.F101.deltaP.fix(0)" - ], - "outputs": [], - "execution_count": 28 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.501210800Z", - "start_time": "2026-02-25T17:35:45.494918400Z" - } - }, - "source": [ - "m.fs.F102.vap_outlet.temperature.fix(375)\n", - "m.fs.F102.deltaP.fix(-200000)" - ], - "outputs": [], - "execution_count": 29 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us fix the purge split fraction to 20% and the outlet pressure of the compressor is set to 350000 Pa. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.507692100Z", - "start_time": "2026-02-25T17:35:45.501210800Z" - } - }, - "source": [ - "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", - "m.fs.C101.outlet.pressure.fix(350000)" - ], - "outputs": [], - "execution_count": 30 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.545059400Z", - "start_time": "2026-02-25T17:35:45.508699400Z" - } - }, - "source": [ - "print(degrees_of_freedom(m))" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n" - ] - } - ], - "execution_count": 31 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5 Initializing the Model\n", - "\n", - "\n", - "\n", - "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", - "\n", - "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", - "\n", - "\n", - "![](HDA_tear_stream.png)\n", - "\n", - "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or\n", - "manually propagating through the flowsheet. The tear stream in this example will be the stream from the mixer to the heater since that is where the\n", - "recycle stream first enters back into the main process.\n", - "\n" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "First, we will highlight some helpful functions that are used in the initialization process." - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.554612100Z", - "start_time": "2026-02-25T17:35:45.546411400Z" - } - }, - "cell_type": "code", - "source": [ - "def initialize_unit(unit):\n", - " from idaes.core.util.exceptions import InitializationError\n", - " import idaes.logger as idaeslog\n", - "\n", - " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 1000,\n", - " \"tol\": 1e-8,\n", - " }\n", - "\n", - " try:\n", - " initializer = unit.default_initializer(solver_options=optarg)\n", - " initializer.initialize(unit, output_level=idaeslog.INFO_LOW)\n", - " except InitializationError:\n", - " solver = get_solver(solver_options=optarg)\n", - " solver.solve(unit)" - ], - "outputs": [], - "execution_count": 32 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This first function will take any unit model and can either initialize the model with its respective default\n", - "initializer, or use a generic solver and the solve the current state of the unit model. Often times a direct\n", - "initialization method will fail while a solving method will converge so having the option for both is helpful.\n", - "\n", - "\n", - "### 5.1 Sequential Decomposition\n", - "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.563940700Z", - "start_time": "2026-02-25T17:35:45.554612100Z" - } - }, - "cell_type": "code", - "source": [ - "def automatic_propagation(m, tear_guesses):\n", - "\n", - " from pyomo.network import SequentialDecomposition\n", - "\n", - " seq = SequentialDecomposition()\n", - " seq.options.select_tear_method = \"heuristic\"\n", - " seq.options.tear_method = \"Wegstein\"\n", - " seq.options.iterLim = 5\n", - "\n", - " # Using the SD tool\n", - " G = seq.create_graph(m)\n", - " heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", - " order = seq.calculation_order(G)\n", - "\n", - " # Pass the tear_guess to the SD tool\n", - " seq.set_guesses_for(heuristic_tear_set[0].destination, tear_guesses)\n", - "\n", - " print(f\"Tear Stream starts at: {heuristic_tear_set[0].destination.name}\")\n", - "\n", - " for o in order:\n", - " print(o[0].name)\n", - "\n", - " seq.run(m, initialize_unit)" - ], - "outputs": [], - "execution_count": 33 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are now ready to initialize our flowsheet in a sequential mode. Note that we specifically set the iteration limit\n", - "to be 5 as we are trying to use this tool only to get a good set of initial values such that IPOPT can then take over\n", - " and solve this flowsheet for us. Uncomment this function call to run the automatic propagation method" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.573285600Z", - "start_time": "2026-02-25T17:35:45.563940700Z" - } - }, - "cell_type": "code", - "source": "# automatic_propagation(m, tear_guesses)", - "outputs": [], - "execution_count": 34 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.2 Manual Propagation Method\n", - "\n", - "This method uses a more direct approach to initialize the flowsheet, using the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", - "Lets define the function that will help us manually propagate and step through the flowsheet" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:45.586548100Z", - "start_time": "2026-02-25T17:35:45.573285600Z" - } - }, - "source": [ - "def manual_propagation(m, tear_guesses):\n", - " from idaes.core.util.initialization import propagate_state\n", - "\n", - " print(f\"The DOF is {degrees_of_freedom(m)} initially\")\n", - " m.fs.s03_expanded.deactivate()\n", - " print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")\n", - "\n", - " for k, v in tear_guesses.items():\n", - " for k1, v1 in v.items():\n", - " getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", - "\n", - " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", - "\n", - " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 300,\n", - " # \"tol\": 1e-10,\n", - " }\n", - "\n", - " solver = get_solver(solver_options=optarg)\n", - "\n", - " initialize_unit(m.fs.H101) # Initialize Heater\n", - " propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", - " initialize_unit(m.fs.R101) # Initialize Reactor\n", - " propagate_state(\n", - " m.fs.s05\n", - " ) # Establish connection between Reactor and First Flash Unit\n", - " initialize_unit(m.fs.F101) # Initialize First Flash Unit\n", - " propagate_state(\n", - " m.fs.s06\n", - " ) # Establish connection between First Flash Unit and Splitter\n", - " propagate_state(\n", - " m.fs.s07\n", - " ) # Establish connection between First Flash Unit and Second Flash Unit\n", - " initialize_unit(m.fs.S101) # Initialize Splitter\n", - " propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", - " initialize_unit(m.fs.C101) # Initialize Compressor\n", - " propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", - " initialize_unit(m.fs.I101) # Initialize Toluene Inlet\n", - " propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", - " initialize_unit(m.fs.I102) # Initialize Hydrogen Inlet\n", - " propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", - " initialize_unit(m.fs.M101) # Initialize Mixer\n", - " propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", - " solver.solve(m.fs.F102)\n", - " propagate_state(\n", - " m.fs.s10\n", - " ) # Establish connection between Second Flash Unit and Benzene Product\n", - " propagate_state(\n", - " m.fs.s11\n", - " ) # Establish connection between Second Flash Unit and Toluene Product\n", - " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", - "\n", - " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 300,\n", - " \"tol\": 1e-8,\n", - " }\n", - " solver = get_solver(\"ipopt_v2\", options=optarg)\n", - " solver.solve(m, tee=False)\n", - "\n", - " for k, v in tear_guesses.items():\n", - " for k1, v1 in v.items():\n", - " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", - "\n", - " m.fs.s03_expanded.activate()\n", - " print(\n", - " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", - " )" - ], - "outputs": [], - "execution_count": 35 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It will first show that the degrees of freedom is correctly at 0 before any streams are deactivated. Once the tear\n", - "stream is deactivated though, the degrees of freedom will be 10. That means 10 variables will have to be defined with\n", - " the tear guesses `tear_guesses`. Then each unit model can be initialized with our same helper function and then can\n", - " propagate the corresponding connection to the following unit models. At the end, the whole flowsheet is solved,\n", - " giving a much better chance for the recycle stream to be used correctly the flowsheet to converge." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.534812500Z", - "start_time": "2026-02-25T17:35:45.588591600Z" - } - }, - "source": "manual_propagation(m, tear_guesses)", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The DOF is 0 initially\n", - "The DOF is 10 after deactivating the tear stream\n", - "The DOF is 0 after setting the tear stream\n", - "The DOF is 0 after unfixing the values and reactivating the tear stream\n" - ] - } - ], - "execution_count": 36 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6 Solving the Model" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.540509400Z", - "start_time": "2026-02-25T17:35:48.534812500Z" - } - }, - "source": [ - "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 1000,\n", - " \"tol\": 1e-8,\n", - "}" - ], - "outputs": [], - "execution_count": 37 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.640201900Z", - "start_time": "2026-02-25T17:35:48.541650800Z" - } - }, - "source": [ - "# Create the solver object\n", - "solver = get_solver(\"ipopt_v2\", options=optarg)\n", - "\n", - "# Solve the model\n", - "results = solver.solve(m, tee=False)" - ], - "outputs": [], - "execution_count": 38 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7 Analyze the results\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.672439Z", - "start_time": "2026-02-25T17:35:48.641645200Z" - } - }, - "source": [ - "m.fs.report()" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Flowsheet : fs Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", - " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", - " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", - " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", - "====================================================================================\n" - ] - } - ], - "execution_count": 39 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What is the total operating cost?" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.678988100Z", - "start_time": "2026-02-25T17:35:48.672439Z" - } - }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "operating cost = $ 419008.28211932775\n" - ] - } - ], - "execution_count": 40 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.694090900Z", - "start_time": "2026-02-25T17:35:48.678988100Z" - } - }, - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Unit : fs.F102 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : 7346.7 : watt : False : (None, None)\n", - " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", - "====================================================================================\n", - "\n", - "benzene purity = 0.8242963521555953\n" - ] - } - ], - "execution_count": 41 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.705653200Z", - "start_time": "2026-02-25T17:35:48.694090900Z" - } - }, - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", - "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", - "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", - "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", - "Total Mole Fraction ('Vap', 'benzene') dimensionless 0.17408 0.084499 \n", - "Total Mole Fraction ('Vap', 'toluene') dimensionless 0.038450 0.0088437 \n", - "Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.16148 0.18592 \n", - "Total Mole Fraction ('Vap', 'methane') dimensionless 0.62599 0.72074 \n", - "Temperature kelvin 771.86 325.00 \n", - "Pressure pascal 3.5000e+05 3.5000e+05 \n" - ] - } - ], - "execution_count": 42 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 8 Optimization\n", - "\n", - "\n", - "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", - "\n", - "Let us try to minimize this cost such that:\n", - "- we are producing at least 0.15 mol/s of benzene in F102 vapor outlet i.e. our product stream\n", - "- purity of benzene i.e. the mole fraction of benzene in F102 vapor outlet is at least 80%\n", - "- restricting the benzene loss in F101 vapor outlet to less than 20%\n", - "\n", - "For this problem, our decision variables are as follows:\n", - "- H101 outlet temperature\n", - "- R101 cooling duty provided\n", - "- F101 outlet temperature\n", - "- F102 outlet temperature\n", - "- F102 deltaP in the flash tank\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us declare our objective function for this problem. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.711266400Z", - "start_time": "2026-02-25T17:35:48.705653200Z" - } - }, - "source": [ - "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ], - "outputs": [], - "execution_count": 43 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we need to unfix the decision variables as we had solved a square problem (degrees of freedom = 0) until now.\n", - "\n", - "Because we are using a stoichiometric reactor, the reactor temperature has no effect on the reaction yield. Additionally, we are using the same cost for heat removal from both the reactor and flash units. Therefore, the optimization algorithm has no reason to prefer heat removal in one place or the other; the solution returned is not locally unique. To remove this indeterminancy and ensure that a consistent solution is returned, we fix the outlet temperature of the reactor." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.717787400Z", - "start_time": "2026-02-25T17:35:48.712769900Z" - } - }, - "source": [ - "m.fs.H101.outlet.temperature.unfix()\n", - "m.fs.R101.heat_duty.unfix()\n", - "m.fs.R101.outlet.temperature.fix(600)\n", - "m.fs.F101.vap_outlet.temperature.unfix()\n", - "m.fs.F102.vap_outlet.temperature.unfix()" - ], - "outputs": [], - "execution_count": 44 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.722789700Z", - "start_time": "2026-02-25T17:35:48.718788400Z" - } - }, - "source": [ - "# Todo: Unfix deltaP for F102\n", - "m.fs.F102.deltaP.unfix()" - ], - "outputs": [], - "execution_count": 45 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we need to set bounds on these decision variables to values shown below:\n", - "\n", - " - H101 outlet temperature [500, 600] K\n", - " - F101 outlet temperature [298, 450] K\n", - " - F102 outlet temperature [298, 450] K\n", - " - F102 outlet pressure [105000, 110000] Pa\n", - "\n", - "Let us first set the variable bound for the H101 outlet temperature as shown below:" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.729091700Z", - "start_time": "2026-02-25T17:35:48.722789700Z" - } - }, - "source": [ - "m.fs.H101.outlet.temperature[0].setlb(500)\n", - "m.fs.H101.outlet.temperature[0].setub(600)" - ], - "outputs": [], - "execution_count": 46 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.733187500Z", - "start_time": "2026-02-25T17:35:48.729091700Z" - } - }, - "source": [ - "# Todo: Set the bounds for reactor outlet temperature\n", - "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", - "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" - ], - "outputs": [], - "execution_count": 47 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us fix the bounds for the rest of the decision variables. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.741354800Z", - "start_time": "2026-02-25T17:35:48.735417200Z" - } - }, - "source": [ - "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", - "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", - "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", - "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ], - "outputs": [], - "execution_count": 48 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, the only things left to define are our constraints on overhead loss in F101, product flow rate and purity in F102. Let us first look at defining a constraint for the overhead loss in F101 where we are restricting the benzene leaving the vapor stream to less than 20 \\% of the benzene available in the reactor outlet. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.746761400Z", - "start_time": "2026-02-25T17:35:48.741354800Z" - } - }, - "source": [ - "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"benzene\"\n", - " ]\n", - " <= 0.20\n", - " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", - ")" - ], - "outputs": [], - "execution_count": 49 - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "solution" - ], - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.752830600Z", - "start_time": "2026-02-25T17:35:48.747769Z" - } - }, - "source": [ - "# Todo: Add minimum product flow constraint\n", - "m.fs.product_flow = Constraint(\n", - " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"benzene\"\n", - " ]\n", - " >= 0.15\n", - ")" - ], - "outputs": [], - "execution_count": 50 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us add the final constraint on product purity or the mole fraction of benzene in the product stream such that it is at least greater than 80%. " - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.758103100Z", - "start_time": "2026-02-25T17:35:48.752830600Z" - } - }, - "source": [ - "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ], - "outputs": [], - "execution_count": 51 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "We have now defined the optimization problem and we are now ready to solve this problem. \n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.864969600Z", - "start_time": "2026-02-25T17:35:48.759128500Z" - } - }, - "source": "results = solver.solve(m, tee=False)", - "outputs": [], - "execution_count": 52 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 8.1 Optimization Results\n", - "\n", - "Display the results and product specifications" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.888864100Z", - "start_time": "2026-02-25T17:35:48.866039700Z" - } - }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "operating cost = $ 312674.2367538264\n", - "\n", - "Product flow rate and purity in F102\n", - "\n", - "====================================================================================\n", - "Unit : fs.F102 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : 8370.2 : watt : False : (None, None)\n", - " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", - "====================================================================================\n", - "\n", - "benzene purity = 0.818829588839798\n", - "\n", - "Overhead loss in F101\n", - "\n", - "====================================================================================\n", - "Unit : fs.F101 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : -42942. : watt : False : (None, None)\n", - " Pressure Change : 0.0000 : pascal : True : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", - "====================================================================================\n" - ] - } - ], - "execution_count": 53 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display optimal values for the decision variables" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:48.939907100Z", - "start_time": "2026-02-25T17:35:48.890367300Z" + "cells": [ + { + "cell_type": "code", + "metadata": { + "tags": [ + "header", + "hide-cell" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:01.286374300Z", + "start_time": "2026-02-25T17:35:01.274737700Z" + } + }, + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ], + "outputs": [], + "execution_count": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# HDA Flowsheet Simulation and Optimization\n", + "\n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2026-1-12\n", + "\n", + "## Learning outcomes\n", + "\n", + "\n", + "- Construct a steady-state flowsheet using the IDAES unit model library\n", + "- Connecting unit models in a flowsheet using Arcs\n", + "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", + "- Formulate and solve an optimization problem\n", + " - Defining an objective function\n", + " - Setting variable bounds\n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", + "     8 Optimizing the Model
\n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", + "\n", + "\n", + "## Problem Statement\n", + "\n", + "Hydrodealkylation is a chemical reaction that often involves reacting\n", + "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", + "simpler aromatic hydrocarbon devoid of functional groups. In this\n", + "example, toluene will be reacted with hydrogen gas at high temperatures\n", + " to form benzene via the following reaction:\n", + "\n", + "**C6H5CH3 + H2 \u2192 C6H6 + CH4**\n", + "\n", + "\n", + "This reaction is often accompanied by an equilibrium side reaction\n", + "which forms diphenyl, which we will neglect for this example.\n", + "\n", + "This example is based on the 1967 AIChE Student Contest problem as\n", + "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", + "McGraw-Hill.\n", + "\n", + "The flowsheet that we will be using for this module is shown below with the stream conditions. We will be processing toluene and hydrogen to produce at least 370 TPY of benzene. As shown in the flowsheet, there are two flash tanks, F101 to separate out the non-condensibles and F102 to further separate the benzene-toluene mixture to improve the benzene purity. Note that typically a distillation column is required to obtain high purity benzene but that is beyond the scope of this workshop. The non-condensibles separated out in F101 will be partially recycled back to M101 and the rest will be either purged or combusted for power generation.We will assume ideal gas for this flowsheet. The properties required for this module are available in the same directory:\n", + "\n", + "- hda_ideal_VLE.py\n", + "- hda_reaction.py\n", + "\n", + "The state variables chosen for the property package are **flows of component by phase, temperature and pressure**. The components considered are: **toluene, hydrogen, benzene and methane**. Therefore, every stream has 8 flow variables, 1 temperature and 1 pressure variable. \n", + "\n", + "![](HDA_flowsheet.png)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", + "\n", + "\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", + "- Constraint (to write constraints)\n", + "- Var (to declare variables)\n", + "- ConcreteModel (to create the concrete model object)\n", + "- Expression (to evaluate values as a function of variables defined in the model)\n", + "- Objective (to define an objective function for optimization)\n", + "- SolverFactory (to solve the problem)\n", + "- TransformationFactory (to apply certain transformations)\n", + "- Arc (to connect two unit models)\n", + "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", + "\n", + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:01.830457200Z", + "start_time": "2026-02-25T17:35:01.290402400Z" + } + }, + "source": [ + "from pyomo.environ import (\n", + " Constraint,\n", + " Var,\n", + " ConcreteModel,\n", + " Expression,\n", + " Objective,\n", + " TransformationFactory,\n", + " value,\n", + ")\n", + "from pyomo.network import Arc" + ], + "outputs": [], + "execution_count": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", + "- Mixer\n", + "- Heater\n", + "- StoichiometricReactor\n", + "- **Flash**\n", + "- Separator (splitter) \n", + "- PressureChanger\n", + "- Product" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.665835Z", + "start_time": "2026-02-25T17:35:01.832975100Z" + } + }, + "source": "from idaes.core import FlowsheetBlock", + "outputs": [], + "execution_count": 3 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.734656600Z", + "start_time": "2026-02-25T17:35:03.667871Z" + } + }, + "source": [ + "from idaes.models.unit_models import (\n", + " PressureChanger,\n", + " Mixer,\n", + " Separator as Splitter,\n", + " Heater,\n", + " StoichiometricReactor,\n", + " Feed,\n", + " Product,\n", + ")" + ], + "outputs": [], + "execution_count": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "Inline Exercise:\n", + "Now, import the remaining unit models highlighted in blue above and run the cell using `Shift+Enter` after typing in the code. \n", + "
\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.752580Z", + "start_time": "2026-02-25T17:35:03.745137800Z" + } + }, + "source": [ + "# Todo: import flash model from idaes.models.unit_models\n", + "from idaes.models.unit_models import Flash" + ], + "outputs": [], + "execution_count": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will also be needing some utility tools to put together the flowsheet and calculate the degrees of freedom. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.761528300Z", + "start_time": "2026-02-25T17:35:03.753588300Z" + } + }, + "source": [ + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "\n", + "# Import idaes logger to set output levels\n", + "from idaes.core.solvers import get_solver" + ], + "outputs": [], + "execution_count": 7 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2 Importing required thermo and reaction package\n", + "\n", + "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", + "\n", + "The reaction package here is very simple as we will be using only a StochiometricReactor and the reaction package consists of the stochiometric coefficients for the reaction and the parameter for the heat of reaction. \n", + "\n", + "Let us import the following modules and they are in the same directory as this jupyter notebook:\n", + "
    \n", + "
  • hda_ideal_VLE as thermo_props
  • \n", + "
  • hda_reaction as reaction_props
  • \n", + "
\n", + "" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.838559500Z", + "start_time": "2026-02-25T17:35:03.761528300Z" + } + }, + "cell_type": "code", + "source": [ + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" + ], + "outputs": [], + "execution_count": 8 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2 Constructing the Flowsheet\n", + "\n", + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.849781Z", + "start_time": "2026-02-25T17:35:03.841636100Z" + } + }, + "source": [ + "m = ConcreteModel()\n", + "m.fs = FlowsheetBlock(dynamic=False)" + ], + "outputs": [], + "execution_count": 9 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now need to add the property packages to the flowsheet. Unlike Module 1, where we only had a thermo property package, for this flowsheet we will also need to add a reaction property package. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.879447Z", + "start_time": "2026-02-25T17:35:03.851130600Z" + } + }, + "source": [ + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", + ")" + ], + "outputs": [], + "execution_count": 10 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.1 Adding Unit Models\n", + "\n", + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.925685100Z", + "start_time": "2026-02-25T17:35:03.881771100Z" + } + }, + "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.M101 = Mixer(\n", + " property_package=m.fs.thermo_params,\n", + " num_inlets=3,\n", + ")\n", + "\n", + "m.fs.H101 = Heater(\n", + " property_package=m.fs.thermo_params,\n", + " has_pressure_change=False,\n", + " has_phase_equilibrium=True,\n", + ")" + ], + "outputs": [], + "execution_count": 11 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.956022500Z", + "start_time": "2026-02-25T17:35:03.935614400Z" + } + }, + "source": [ + "# Todo: Add reactor with the specifications above\n", + "m.fs.R101 = StoichiometricReactor(\n", + " property_package=m.fs.thermo_params,\n", + " reaction_package=m.fs.reaction_params,\n", + " has_heat_of_reaction=True,\n", + " has_heat_transfer=True,\n", + " has_pressure_change=False,\n", + ")" + ], + "outputs": [], + "execution_count": 13 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now add the Flash(assign the name F101) and pass the following arguments:\n", + "
    \n", + "
  • \"property_package\": m.fs.thermo_params
  • \n", + "
  • \"has_heat_transfer\": True
  • \n", + "
  • \"has_pressure_change\": False
  • \n", + "
" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.979104400Z", + "start_time": "2026-02-25T17:35:03.958076200Z" + } + }, + "source": [ + "m.fs.F101 = Flash(\n", + " property_package=m.fs.thermo_params,\n", + " has_heat_transfer=True,\n", + " has_pressure_change=True,\n", + ")" + ], + "outputs": [], + "execution_count": 14 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.031371300Z", + "start_time": "2026-02-25T17:35:03.981638100Z" + } + }, + "source": [ + "m.fs.S101 = Splitter(\n", + " property_package=m.fs.thermo_params,\n", + " ideal_separation=False,\n", + " outlet_list=[\"purge\", \"recycle\"],\n", + ")\n", + "\n", + "\n", + "m.fs.C101 = PressureChanger(\n", + " property_package=m.fs.thermo_params,\n", + " compressor=True,\n", + " thermodynamic_assumption=ThermodynamicAssumption.isothermal,\n", + ")\n", + "\n", + "m.fs.F102 = Flash(\n", + " property_package=m.fs.thermo_params,\n", + " has_heat_transfer=True,\n", + " has_pressure_change=True,\n", + ")" + ], + "outputs": [], + "execution_count": 15 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.049278900Z", + "start_time": "2026-02-25T17:35:04.033910400Z" + } + }, + "source": [ + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" + ], + "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.2 Connecting Unit Models using Arcs\n", + "\n", + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](HDA_flowsheet.png)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.059097Z", + "start_time": "2026-02-25T17:35:04.051649500Z" + } + }, + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.074873700Z", + "start_time": "2026-02-25T17:35:04.067198800Z" + } + }, + "source": [ + "# Todo: Connect the H101 outlet to R101 inlet\n", + "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" + ], + "outputs": [], + "execution_count": 19 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will now be connecting the rest of the flowsheet as shown below. Notice how the outlet names are different for the flash tanks F101 and F102 as they have a vapor and a liquid outlet. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.082717500Z", + "start_time": "2026-02-25T17:35:04.075379Z" + } + }, + "source": [ + "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", + "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", + "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" + ], + "outputs": [], + "execution_count": 20 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.091461Z", + "start_time": "2026-02-25T17:35:04.083716700Z" + } + }, + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ], + "outputs": [], + "execution_count": 21 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows:" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.116142500Z", + "start_time": "2026-02-25T17:35:04.092591700Z" + } + }, + "source": [ + "TransformationFactory(\"network.expand_arcs\").apply_to(m)" + ], + "outputs": [], + "execution_count": 22 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.3 Adding expressions to compute purity and operating costs\n", + "\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", + "\n", + "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us first add an Expression to compute the mole fraction of benzene in the `vap_outlet` of F102 which is our product stream. Please note that the var flow_mol_phase_comp has the index - [time, phase, component]. As this is a steady-state flowsheet, the time index by default is 0. The valid phases are [\"Liq\", \"Vap\"]. Similarly the valid component list is [\"benzene\", \"toluene\", \"hydrogen\", \"methane\"]." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.126991900Z", + "start_time": "2026-02-25T17:35:04.118294Z" + } + }, + "source": [ + "m.fs.purity = Expression(\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " / (\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", + " )\n", + ")" + ], + "outputs": [], + "execution_count": 23 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let us add an expression to compute the cooling cost assuming a cost of 0.212E-4 $/kW. Note that cooling utility is required for the reactor (R101) and the first flash (F101). " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.134981600Z", + "start_time": "2026-02-25T17:35:04.126991900Z" + } + }, + "source": [ + "m.fs.cooling_cost = Expression(\n", + " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", + ")" + ], + "outputs": [], + "execution_count": 24 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Now, let us add an expression to compute the heating cost assuming the utility cost as follows:\n", + "
    \n", + "
  • 2.2E-4 dollars/kW for H101
  • \n", + "
  • 1.9E-4 dollars/kW for F102
  • \n", + "
\n", + "Note that the heat duty is in units of watt (J/s). " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.142918500Z", + "start_time": "2026-02-25T17:35:04.134981600Z" + } + }, + "source": [ + "m.fs.heating_cost = Expression(\n", + " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", + ")" + ], + "outputs": [], + "execution_count": 25 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now add an expression to compute the total operating cost per year which is basically the sum of the cooling and heating cost we defined above. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.151633300Z", + "start_time": "2026-02-25T17:35:04.143918400Z" + } + }, + "source": [ + "m.fs.operating_cost = Expression(\n", + " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", + ")" + ], + "outputs": [], + "execution_count": 26 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", + "\n", + "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.183600800Z", + "start_time": "2026-02-25T17:35:04.152655800Z" + } + }, + "source": [ + "print(degrees_of_freedom(m))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], + "execution_count": 27 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note\n", + "that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to\n", + "help with convergence and initializing. We will be importing a function that will specify the inlet conditions for\n", + "this example." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.227743300Z", + "start_time": "2026-02-25T17:35:04.218810900Z" + } + }, + "source": [ + "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", + "\n", + "tear_guesses = fix_inlet_states(m)" + ], + "outputs": [], + "execution_count": 29 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2 Fixing unit model specifications\n", + "\n", + "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.235882200Z", + "start_time": "2026-02-25T17:35:04.227743300Z" + } + }, + "source": [ + "m.fs.H101.outlet.temperature.fix(600)" + ], + "outputs": [], + "execution_count": 30 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the StoichiometricReactor, we have to define the conversion in terms of toluene. This requires us to create a new variable for specifying the conversion and adding a Constraint that defines the conversion with respect to toluene. The second degree of freedom for the reactor is to define the heat duty. In this case, let us assume the reactor to be adiabatic i.e. Q = 0. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.257770300Z", + "start_time": "2026-02-25T17:35:04.236888500Z" + } + }, + "source": [ + "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", + "\n", + "m.fs.R101.conv_constraint = Constraint(\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", + " == (\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", + " )\n", + ")\n", + "\n", + "m.fs.R101.conversion.fix(0.75)\n", + "m.fs.R101.heat_duty.fix(0)" + ], + "outputs": [], + "execution_count": 31 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Flash conditions for F101 can be set as follows. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.268846Z", + "start_time": "2026-02-25T17:35:04.260299600Z" + } + }, + "source": [ + "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", + "m.fs.F101.deltaP.fix(0)" + ], + "outputs": [], + "execution_count": 32 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.288481300Z", + "start_time": "2026-02-25T17:35:04.279196300Z" + } + }, + "source": [ + "m.fs.F102.vap_outlet.temperature.fix(375)\n", + "m.fs.F102.deltaP.fix(-200000)" + ], + "outputs": [], + "execution_count": 34 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us fix the purge split fraction to 20% and the outlet pressure of the compressor is set to 350000 Pa. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.302496300Z", + "start_time": "2026-02-25T17:35:04.289482700Z" + } + }, + "source": [ + "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", + "m.fs.C101.outlet.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 35 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.340811100Z", + "start_time": "2026-02-25T17:35:04.313761800Z" + } + }, + "source": [ + "print(degrees_of_freedom(m))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "execution_count": 37 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5 Initializing the Model\n", + "\n", + "\n", + "\n", + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear\u2010stream method is necessary because it \u201cbreaks\u201d this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization\u2014and ultimately steady\u2010state convergence\u2014impossible.\n", + "\n", + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", + "\n", + "\n", + "![](HDA_tear_stream.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or\n", + "manually propagating through the flowsheet. The tear stream in this example will be the stream from the mixer to the heater since that is where the\n", + "recycle stream first enters back into the main process.\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "First, we will highlight some helpful functions that are used in the initialization process." + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.386344500Z", + "start_time": "2026-02-25T17:35:04.376804600Z" + } + }, + "cell_type": "code", + "source": [ + "def initialize_unit(unit):\n", + " from idaes.core.util.exceptions import InitializationError\n", + " import idaes.logger as idaeslog\n", + "\n", + " optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + " }\n", + "\n", + " try:\n", + " initializer = unit.default_initializer(solver_options=optarg)\n", + " initializer.initialize(unit, output_level=idaeslog.INFO_LOW)\n", + " except InitializationError:\n", + " solver = get_solver(solver_options=optarg)\n", + " solver.solve(unit)" + ], + "outputs": [], + "execution_count": 39 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This first function will take any unit model and can either initialize the model with its respective default\n", + "initializer, or use a generic solver and the solve the current state of the unit model. Often times a direct\n", + "initialization method will fail while a solving method will converge so having the option for both is helpful.\n", + "\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.394802500Z", + "start_time": "2026-02-25T17:35:04.386344500Z" + } + }, + "cell_type": "code", + "source": [ + "def automatic_propagation(m, tear_guesses):\n", + "\n", + " from pyomo.network import SequentialDecomposition\n", + "\n", + " seq = SequentialDecomposition()\n", + " seq.options.select_tear_method = \"heuristic\"\n", + " seq.options.tear_method = \"Wegstein\"\n", + " seq.options.iterLim = 5\n", + "\n", + " # Using the SD tool\n", + " G = seq.create_graph(m)\n", + " heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", + " order = seq.calculation_order(G)\n", + "\n", + " # Pass the tear_guess to the SD tool\n", + " seq.set_guesses_for(heuristic_tear_set[0].destination, tear_guesses)\n", + "\n", + " print(f\"Tear Stream starts at: {heuristic_tear_set[0].destination.name}\")\n", + "\n", + " for o in order:\n", + " print(o[0].name)\n", + "\n", + " seq.run(m, initialize_unit)" + ], + "outputs": [], + "execution_count": 40 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We are now ready to initialize our flowsheet in a sequential mode. Note that we specifically set the iteration limit\n", + "to be 5 as we are trying to use this tool only to get a good set of initial values such that IPOPT can then take over\n", + " and solve this flowsheet for us. Uncomment this function call to run the automatic propagation method" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.404491500Z", + "start_time": "2026-02-25T17:35:04.396317500Z" + } + }, + "cell_type": "code", + "source": "# automatic_propagation(m, tear_guesses)", + "outputs": [], + "execution_count": 41 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, using the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets define the function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.417815100Z", + "start_time": "2026-02-25T17:35:04.404995800Z" + } + }, + "source": [ + "def manual_propagation(m, tear_guesses):\n", + " from idaes.core.util.initialization import propagate_state\n", + "\n", + " print(f\"The DOF is {degrees_of_freedom(m)} initially\")\n", + " m.fs.s03_expanded.deactivate()\n", + " print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")\n", + "\n", + " for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "\n", + " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", + "\n", + " optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " # \"tol\": 1e-10,\n", + " }\n", + "\n", + " solver = get_solver(solver_options=optarg)\n", + "\n", + " initialize_unit(m.fs.H101) # Initialize Heater\n", + " propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + " initialize_unit(m.fs.R101) # Initialize Reactor\n", + " propagate_state(\n", + " m.fs.s05\n", + " ) # Establish connection between Reactor and First Flash Unit\n", + " initialize_unit(m.fs.F101) # Initialize First Flash Unit\n", + " propagate_state(\n", + " m.fs.s06\n", + " ) # Establish connection between First Flash Unit and Splitter\n", + " propagate_state(\n", + " m.fs.s07\n", + " ) # Establish connection between First Flash Unit and Second Flash Unit\n", + " initialize_unit(m.fs.S101) # Initialize Splitter\n", + " propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + " initialize_unit(m.fs.C101) # Initialize Compressor\n", + " propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + " initialize_unit(m.fs.I101) # Initialize Toluene Inlet\n", + " propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + " initialize_unit(m.fs.I102) # Initialize Hydrogen Inlet\n", + " propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + " initialize_unit(m.fs.M101) # Initialize Mixer\n", + " propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + " solver.solve(m.fs.F102)\n", + " propagate_state(\n", + " m.fs.s10\n", + " ) # Establish connection between Second Flash Unit and Benzene Product\n", + " propagate_state(\n", + " m.fs.s11\n", + " ) # Establish connection between Second Flash Unit and Toluene Product\n", + " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", + "\n", + " optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + " }\n", + " solver = get_solver(\"ipopt_v2\", options=optarg)\n", + " solver.solve(m, tee=False)\n", + "\n", + " for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", + "\n", + " m.fs.s03_expanded.activate()\n", + " print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + " )" + ], + "outputs": [], + "execution_count": 42 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It will first show that the degrees of freedom is correctly at 0 before any streams are deactivated. Once the tear\n", + "stream is deactivated though, the degrees of freedom will be 10. That means 10 variables will have to be defined with\n", + " the tear guesses `tear_guesses`. Then each unit model can be initialized with our same helper function and then can\n", + " propagate the corresponding connection to the following unit models. At the end, the whole flowsheet is solved,\n", + " giving a much better chance for the recycle stream to be used correctly the flowsheet to converge." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.145125500Z", + "start_time": "2026-02-25T17:35:04.419335500Z" + } + }, + "source": "manual_propagation(m, tear_guesses)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 initially\n", + "The DOF is 10 after deactivating the tear stream\n", + "The DOF is 0 after setting the tear stream\n", + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "execution_count": 43 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.161129400Z", + "start_time": "2026-02-25T17:35:07.146644300Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ], + "outputs": [], + "execution_count": 44 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.272798500Z", + "start_time": "2026-02-25T17:35:07.170980400Z" + } + }, + "source": [ + "# Create the solver object\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "\n", + "# Solve the model\n", + "results = solver.solve(m, tee=False)" + ], + "outputs": [], + "execution_count": 46 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7 Analyze the results\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.337983600Z", + "start_time": "2026-02-25T17:35:07.303479400Z" + } + }, + "source": [ + "m.fs.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "execution_count": 49 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What is the total operating cost?" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.355013500Z", + "start_time": "2026-02-25T17:35:07.346055600Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 419008.28211932775\n" + ] + } + ], + "execution_count": 50 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.469810Z", + "start_time": "2026-02-25T17:35:07.452663800Z" + } + }, + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 7346.7 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 0.26712 - - \n", + " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8242963521555953\n" + ] + } + ], + "execution_count": 52 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.503351300Z", + "start_time": "2026-02-25T17:35:07.487979400Z" + } + }, + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", + "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", + "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", + "Total Mole Fraction ('Vap', 'benzene') dimensionless 0.17408 0.084499 \n", + "Total Mole Fraction ('Vap', 'toluene') dimensionless 0.038450 0.0088437 \n", + "Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.16148 0.18592 \n", + "Total Mole Fraction ('Vap', 'methane') dimensionless 0.62599 0.72074 \n", + "Temperature kelvin 771.86 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], + "execution_count": 54 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8 Optimization\n", + "\n", + "\n", + "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", + "\n", + "Let us try to minimize this cost such that:\n", + "- we are producing at least 0.15 mol/s of benzene in F102 vapor outlet i.e. our product stream\n", + "- purity of benzene i.e. the mole fraction of benzene in F102 vapor outlet is at least 80%\n", + "- restricting the benzene loss in F101 vapor outlet to less than 20%\n", + "\n", + "For this problem, our decision variables are as follows:\n", + "- H101 outlet temperature\n", + "- R101 cooling duty provided\n", + "- F101 outlet temperature\n", + "- F102 outlet temperature\n", + "- F102 deltaP in the flash tank\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us declare our objective function for this problem. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.523495700Z", + "start_time": "2026-02-25T17:35:07.513232100Z" + } + }, + "source": [ + "m.fs.objective = Objective(expr=m.fs.operating_cost)" + ], + "outputs": [], + "execution_count": 55 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we need to unfix the decision variables as we had solved a square problem (degrees of freedom = 0) until now.\n", + "\n", + "Because we are using a stoichiometric reactor, the reactor temperature has no effect on the reaction yield. Additionally, we are using the same cost for heat removal from both the reactor and flash units. Therefore, the optimization algorithm has no reason to prefer heat removal in one place or the other; the solution returned is not locally unique. To remove this indeterminancy and ensure that a consistent solution is returned, we fix the outlet temperature of the reactor." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.538051100Z", + "start_time": "2026-02-25T17:35:07.528058900Z" + } + }, + "source": [ + "m.fs.H101.outlet.temperature.unfix()\n", + "m.fs.R101.heat_duty.unfix()\n", + "m.fs.R101.outlet.temperature.fix(600)\n", + "m.fs.F101.vap_outlet.temperature.unfix()\n", + "m.fs.F102.vap_outlet.temperature.unfix()" + ], + "outputs": [], + "execution_count": 56 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.578318700Z", + "start_time": "2026-02-25T17:35:07.571295800Z" + } + }, + "source": [ + "# Todo: Unfix deltaP for F102\n", + "m.fs.F102.deltaP.unfix()" + ], + "outputs": [], + "execution_count": 58 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we need to set bounds on these decision variables to values shown below:\n", + "\n", + " - H101 outlet temperature [500, 600] K\n", + " - F101 outlet temperature [298, 450] K\n", + " - F102 outlet temperature [298, 450] K\n", + " - F102 outlet pressure [105000, 110000] Pa\n", + "\n", + "Let us first set the variable bound for the H101 outlet temperature as shown below:" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.627054600Z", + "start_time": "2026-02-25T17:35:07.619525700Z" + } + }, + "source": [ + "m.fs.H101.outlet.temperature[0].setlb(500)\n", + "m.fs.H101.outlet.temperature[0].setub(600)" + ], + "outputs": [], + "execution_count": 60 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.652892600Z", + "start_time": "2026-02-25T17:35:07.643756900Z" + } + }, + "source": [ + "# Todo: Set the bounds for reactor outlet temperature\n", + "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", + "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" + ], + "outputs": [], + "execution_count": 62 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us fix the bounds for the rest of the decision variables. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.662831700Z", + "start_time": "2026-02-25T17:35:07.654919400Z" + } + }, + "source": [ + "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", + "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", + "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", + "m.fs.F102.vap_outlet.pressure[0].setub(110000)" + ], + "outputs": [], + "execution_count": 63 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, the only things left to define are our constraints on overhead loss in F101, product flow rate and purity in F102. Let us first look at defining a constraint for the overhead loss in F101 where we are restricting the benzene leaving the vapor stream to less than 20 \\% of the benzene available in the reactor outlet. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.673507300Z", + "start_time": "2026-02-25T17:35:07.666381200Z" + } + }, + "source": [ + "m.fs.overhead_loss = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + ")" + ], + "outputs": [], + "execution_count": 64 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.707964Z", + "start_time": "2026-02-25T17:35:07.699126100Z" + } + }, + "source": [ + "# Todo: Add minimum product flow constraint\n", + "m.fs.product_flow = Constraint(\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " >= 0.15\n", + ")" + ], + "outputs": [], + "execution_count": 66 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us add the final constraint on product purity or the mole fraction of benzene in the product stream such that it is at least greater than 80%. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.718982700Z", + "start_time": "2026-02-25T17:35:07.711201900Z" + } + }, + "source": [ + "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" + ], + "outputs": [], + "execution_count": 67 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "We have now defined the optimization problem and we are now ready to solve this problem. \n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.837157700Z", + "start_time": "2026-02-25T17:35:07.721454600Z" + } + }, + "source": "results = solver.solve(m, tee=False)", + "outputs": [], + "execution_count": 68 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 8.1 Optimization Results\n", + "\n", + "Display the results and product specifications" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.883912Z", + "start_time": "2026-02-25T17:35:07.847804400Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 312674.2367538264\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 8370.2 : watt : False : (None, None)\n", + " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 0.28812 - - \n", + " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", + " Temperature kelvin 301.88 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", + " temperature kelvin - 362.93 362.93 \n", + " pressure pascal - 1.0500e+05 1.0500e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.818829588839798\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -42942. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", + " Total Molar Flowrate Vap mole / second 1.9480 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", + " Temperature kelvin 600.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", + " temperature kelvin - 301.88 301.88 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 70 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display optimal values for the decision variables" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.924695400Z", + "start_time": "2026-02-25T17:35:07.893574600Z" + } + }, + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 heat duty = -13766.243 W\n", + "\n", + "F101 outlet temperature = 301.881 K\n", + "\n", + "F102 outlet temperature = 362.935 K\n", + "F102 outlet pressure = 105000.000 Pa\n", + "\n" + ] + } + ], + "execution_count": 72 } - }, - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Values:\n", - "\n", - "H101 outlet temperature = 500.000 K\n", - "\n", - "R101 heat duty = -13766.243 W\n", - "\n", - "F101 outlet temperature = 301.881 K\n", - "\n", - "F102 outlet temperature = 362.935 K\n", - "F102 outlet pressure = 105000.000 Pa\n", - "\n" - ] + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" } - ], - "execution_count": 54 - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb index c5a7f085..f5f0243b 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb @@ -1,2448 +1,2052 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:49.451188700Z", - "start_time": "2026-02-25T17:35:49.443870Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:36:58.386034Z", - "iopub.status.busy": "2026-02-25T17:36:58.386034Z", - "iopub.status.idle": "2026-02-25T17:36:58.389677Z", - "shell.execute_reply": "2026-02-25T17:36:58.389677Z" - }, - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (idaes IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "# HDA Flowsheet Simulation and Optimization\n", - "\n", - "Author: Jaffer Ghouse
\n", - "Maintainer: Tanner Polley
\n", - "Updated: 2026-1-12\n", - "\n", - "## Learning outcomes\n", - "\n", - "\n", - "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", - "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Formulate and solve an optimization problem\n", - " - Defining an objective function\n", - " - Setting variable bounds\n", - " - Adding additional constraints\n", - "\n", - "\n", - "The general workflow of setting up an IDAES flowsheet is the following:\n", - "\n", - "     1 Importing Modules
\n", - "     2 Building a Model
\n", - "     3 Scaling the Model
\n", - "     4 Specifying the Model
\n", - "     5 Initializing the Model
\n", - "     6 Solving the Model
\n", - "     7 Analyzing and Visualizing the Results
\n", - "     8 Optimizing the Model
\n", - "\n", - "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", - "\n", - "\n", - "## Problem Statement\n", - "\n", - "Hydrodealkylation is a chemical reaction that often involves reacting\n", - "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", - "simpler aromatic hydrocarbon devoid of functional groups. In this\n", - "example, toluene will be reacted with hydrogen gas at high temperatures\n", - " to form benzene via the following reaction:\n", - "\n", - "**C6H5CH3 + H2 → C6H6 + CH4**\n", - "\n", - "\n", - "This reaction is often accompanied by an equilibrium side reaction\n", - "which forms diphenyl, which we will neglect for this example.\n", - "\n", - "This example is based on the 1967 AIChE Student Contest problem as\n", - "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", - "McGraw-Hill.\n", - "\n", - "The flowsheet that we will be using for this module is shown below with the stream conditions. We will be processing toluene and hydrogen to produce at least 370 TPY of benzene. As shown in the flowsheet, there are two flash tanks, F101 to separate out the non-condensibles and F102 to further separate the benzene-toluene mixture to improve the benzene purity. Note that typically a distillation column is required to obtain high purity benzene but that is beyond the scope of this workshop. The non-condensibles separated out in F101 will be partially recycled back to M101 and the rest will be either purged or combusted for power generation.We will assume ideal gas for this flowsheet. The properties required for this module are available in the same directory:\n", - "\n", - "- hda_ideal_VLE.py\n", - "- hda_reaction.py\n", - "\n", - "The state variables chosen for the property package are **flows of component by phase, temperature and pressure**. The components considered are: **toluene, hydrogen, benzene and methane**. Therefore, every stream has 8 flow variables, 1 temperature and 1 pressure variable. \n", - "\n", - "![](HDA_flowsheet.png)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1 Importing Modules\n", - "### 1.1 Importing required Pyomo and IDAES components\n", - "\n", - "\n", - "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", - "- Constraint (to write constraints)\n", - "- Var (to declare variables)\n", - "- ConcreteModel (to create the concrete model object)\n", - "- Expression (to evaluate values as a function of variables defined in the model)\n", - "- Objective (to define an objective function for optimization)\n", - "- SolverFactory (to solve the problem)\n", - "- TransformationFactory (to apply certain transformations)\n", - "- Arc (to connect two unit models)\n", - "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", - "\n", - "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:49.951979200Z", - "start_time": "2026-02-25T17:35:49.452196900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:36:58.391701Z", - "iopub.status.busy": "2026-02-25T17:36:58.390694Z", - "iopub.status.idle": "2026-02-25T17:36:58.919981Z", - "shell.execute_reply": "2026-02-25T17:36:58.919981Z" - } - }, - "outputs": [], - "source": [ - "from pyomo.environ import (\n", - " Constraint,\n", - " Var,\n", - " ConcreteModel,\n", - " Expression,\n", - " Objective,\n", - " TransformationFactory,\n", - " value,\n", - ")\n", - "from pyomo.network import Arc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", - "- Feed\n", - "- Mixer\n", - "- Heater\n", - "- StoichiometricReactor\n", - "- **Flash**\n", - "- Separator (splitter) \n", - "- PressureChanger\n", - "- Product" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.683950100Z", - "start_time": "2026-02-25T17:35:49.953987Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:36:58.920992Z", - "iopub.status.busy": "2026-02-25T17:36:58.920992Z", - "iopub.status.idle": "2026-02-25T17:37:00.933980Z", - "shell.execute_reply": "2026-02-25T17:37:00.933980Z" - } - }, - "outputs": [], - "source": [ - "from idaes.core import FlowsheetBlock" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.750421600Z", - "start_time": "2026-02-25T17:35:51.687495400Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:00.935490Z", - "iopub.status.busy": "2026-02-25T17:37:00.935490Z", - "iopub.status.idle": "2026-02-25T17:37:00.990160Z", - "shell.execute_reply": "2026-02-25T17:37:00.990160Z" - } - }, - "outputs": [], - "source": [ - "from idaes.models.unit_models import (\n", - " PressureChanger,\n", - " Mixer,\n", - " Separator as Splitter,\n", - " Heater,\n", - " StoichiometricReactor,\n", - " Feed,\n", - " Product,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Now, import the remaining unit models highlighted in blue above and run the cell using `Shift+Enter` after typing in the code. \n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.757957Z", - "start_time": "2026-02-25T17:35:51.752101800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:00.992178Z", - "iopub.status.busy": "2026-02-25T17:37:00.991171Z", - "iopub.status.idle": "2026-02-25T17:37:00.994194Z", - "shell.execute_reply": "2026-02-25T17:37:00.994194Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: import flash model from idaes.models.unit_models\n", - "from idaes.models.unit_models import Flash" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will also be needing some utility tools to put together the flowsheet and calculate the degrees of freedom. " - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.781775200Z", - "start_time": "2026-02-25T17:35:51.758992100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:00.994706Z", - "iopub.status.busy": "2026-02-25T17:37:00.994706Z", - "iopub.status.idle": "2026-02-25T17:37:00.998048Z", - "shell.execute_reply": "2026-02-25T17:37:00.998048Z" - } - }, - "outputs": [], - "source": [ - "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "\n", - "# Import idaes logger to set output levels\n", - "from idaes.core.solvers import get_solver" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.2 Importing required thermo and reaction package\n", - "\n", - "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", - "\n", - "The reaction package here is very simple as we will be using only a StochiometricReactor and the reaction package consists of the stochiometric coefficients for the reaction and the parameter for the heat of reaction. \n", - "\n", - "Let us import the following modules and they are in the same directory as this jupyter notebook:\n", - "
    \n", - "
  • hda_ideal_VLE as thermo_props
  • \n", - "
  • hda_reaction as reaction_props
  • \n", - "
\n", - "" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.830263200Z", - "start_time": "2026-02-25T17:35:51.784804600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:00.999064Z", - "iopub.status.busy": "2026-02-25T17:37:00.999064Z", - "iopub.status.idle": "2026-02-25T17:37:01.041310Z", - "shell.execute_reply": "2026-02-25T17:37:01.041310Z" - } - }, - "outputs": [], - "source": [ - "from idaes.models.properties.modular_properties.base.generic_property import (\n", - " GenericParameterBlock,\n", - ")\n", - "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", - " GenericReactionParameterBlock,\n", - ")\n", - "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", - "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2 Constructing the Flowsheet\n", - "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.840617900Z", - "start_time": "2026-02-25T17:35:51.832798500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.043334Z", - "iopub.status.busy": "2026-02-25T17:37:01.042328Z", - "iopub.status.idle": "2026-02-25T17:37:01.046289Z", - "shell.execute_reply": "2026-02-25T17:37:01.046289Z" - } - }, - "outputs": [], - "source": [ - "m = ConcreteModel()\n", - "m.fs = FlowsheetBlock(dynamic=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now need to add the property packages to the flowsheet. Unlike Module 1, where we only had a thermo property package, for this flowsheet we will also need to add a reaction property package. " - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.925629300Z", - "start_time": "2026-02-25T17:35:51.840617900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.047302Z", - "iopub.status.busy": "2026-02-25T17:37:01.047302Z", - "iopub.status.idle": "2026-02-25T17:37:01.069166Z", - "shell.execute_reply": "2026-02-25T17:37:01.069166Z" - } - }, - "outputs": [], - "source": [ - "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", - "m.fs.reaction_params = GenericReactionParameterBlock(\n", - " property_package=m.fs.thermo_params, **reaction_config\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.1 Adding Unit Models\n", - "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:51.977923800Z", - "start_time": "2026-02-25T17:35:51.926723600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.071179Z", - "iopub.status.busy": "2026-02-25T17:37:01.070178Z", - "iopub.status.idle": "2026-02-25T17:37:01.107778Z", - "shell.execute_reply": "2026-02-25T17:37:01.107778Z" - } - }, - "outputs": [], - "source": [ - "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", - "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", - "\n", - "m.fs.M101 = Mixer(\n", - " property_package=m.fs.thermo_params,\n", - " num_inlets=3,\n", - ")\n", - "\n", - "m.fs.H101 = Heater(\n", - " property_package=m.fs.thermo_params,\n", - " has_pressure_change=False,\n", - " has_phase_equilibrium=True,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.004722200Z", - "start_time": "2026-02-25T17:35:51.983010Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.108796Z", - "iopub.status.busy": "2026-02-25T17:37:01.108796Z", - "iopub.status.idle": "2026-02-25T17:37:01.123404Z", - "shell.execute_reply": "2026-02-25T17:37:01.123404Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Add reactor with the specifications above\n", - "m.fs.R101 = StoichiometricReactor(\n", - " property_package=m.fs.thermo_params,\n", - " reaction_package=m.fs.reaction_params,\n", - " has_heat_of_reaction=True,\n", - " has_heat_transfer=True,\n", - " has_pressure_change=False,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us now add the Flash(assign the name F101) and pass the following arguments:\n", - "
    \n", - "
  • \"property_package\": m.fs.thermo_params
  • \n", - "
  • \"has_heat_transfer\": True
  • \n", - "
  • \"has_pressure_change\": False
  • \n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.030379900Z", - "start_time": "2026-02-25T17:35:52.005747400Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.124915Z", - "iopub.status.busy": "2026-02-25T17:37:01.124915Z", - "iopub.status.idle": "2026-02-25T17:37:01.139798Z", - "shell.execute_reply": "2026-02-25T17:37:01.139798Z" - } - }, - "outputs": [], - "source": [ - "m.fs.F101 = Flash(\n", - " property_package=m.fs.thermo_params,\n", - " has_heat_transfer=True,\n", - " has_pressure_change=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.072038400Z", - "start_time": "2026-02-25T17:35:52.030379900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.141309Z", - "iopub.status.busy": "2026-02-25T17:37:01.141309Z", - "iopub.status.idle": "2026-02-25T17:37:01.175711Z", - "shell.execute_reply": "2026-02-25T17:37:01.175711Z" - } - }, - "outputs": [], - "source": [ - "m.fs.S101 = Splitter(\n", - " property_package=m.fs.thermo_params,\n", - " ideal_separation=False,\n", - " outlet_list=[\"purge\", \"recycle\"],\n", - ")\n", - "\n", - "\n", - "m.fs.C101 = PressureChanger(\n", - " property_package=m.fs.thermo_params,\n", - " compressor=True,\n", - " thermodynamic_assumption=ThermodynamicAssumption.isothermal,\n", - ")\n", - "\n", - "m.fs.F102 = Flash(\n", - " property_package=m.fs.thermo_params,\n", - " has_heat_transfer=True,\n", - " has_pressure_change=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.086151100Z", - "start_time": "2026-02-25T17:35:52.073045900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.177736Z", - "iopub.status.busy": "2026-02-25T17:37:01.176727Z", - "iopub.status.idle": "2026-02-25T17:37:01.186976Z", - "shell.execute_reply": "2026-02-25T17:37:01.186472Z" - } - }, - "outputs": [], - "source": [ - "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", - "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", - "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.2 Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![](HDA_flowsheet.png)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.141606200Z", - "start_time": "2026-02-25T17:35:52.087163500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.188496Z", - "iopub.status.busy": "2026-02-25T17:37:01.187479Z", - "iopub.status.idle": "2026-02-25T17:37:01.190941Z", - "shell.execute_reply": "2026-02-25T17:37:01.190941Z" - } - }, - "outputs": [], - "source": [ - "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", - "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.149032900Z", - "start_time": "2026-02-25T17:35:52.142612200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.191951Z", - "iopub.status.busy": "2026-02-25T17:37:01.191951Z", - "iopub.status.idle": "2026-02-25T17:37:01.195109Z", - "shell.execute_reply": "2026-02-25T17:37:01.195109Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Connect the H101 outlet to R101 inlet\n", - "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now be connecting the rest of the flowsheet as shown below. Notice how the outlet names are different for the flash tanks F101 and F102 as they have a vapor and a liquid outlet. " - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.159140400Z", - "start_time": "2026-02-25T17:35:52.152068Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.196621Z", - "iopub.status.busy": "2026-02-25T17:37:01.196621Z", - "iopub.status.idle": "2026-02-25T17:37:01.199500Z", - "shell.execute_reply": "2026-02-25T17:37:01.199500Z" - } - }, - "outputs": [], - "source": [ - "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", - "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", - "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", - "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.166812500Z", - "start_time": "2026-02-25T17:35:52.160150900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.200704Z", - "iopub.status.busy": "2026-02-25T17:37:01.200704Z", - "iopub.status.idle": "2026-02-25T17:37:01.204254Z", - "shell.execute_reply": "2026-02-25T17:37:01.204254Z" - } - }, - "outputs": [], - "source": [ - "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", - "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", - "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.191818800Z", - "start_time": "2026-02-25T17:35:52.166812500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.204766Z", - "iopub.status.busy": "2026-02-25T17:37:01.204766Z", - "iopub.status.idle": "2026-02-25T17:37:01.223582Z", - "shell.execute_reply": "2026-02-25T17:37:01.223582Z" - } - }, - "outputs": [], - "source": [ - "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.3 Adding expressions to compute purity and operating costs\n", - "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", - "\n", - "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us first add an Expression to compute the mole fraction of benzene in the `vap_outlet` of F102 which is our product stream. Please note that the var flow_mol_phase_comp has the index - [time, phase, component]. As this is a steady-state flowsheet, the time index by default is 0. The valid phases are [\"Liq\", \"Vap\"]. Similarly the valid component list is [\"benzene\", \"toluene\", \"hydrogen\", \"methane\"]." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.198658300Z", - "start_time": "2026-02-25T17:35:52.192833400Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.224608Z", - "iopub.status.busy": "2026-02-25T17:37:01.224608Z", - "iopub.status.idle": "2026-02-25T17:37:01.228141Z", - "shell.execute_reply": "2026-02-25T17:37:01.228141Z" - } - }, - "outputs": [], - "source": [ - "m.fs.purity = Expression(\n", - " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"benzene\"\n", - " ]\n", - " / (\n", - " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", - " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"toluene\"\n", - " ]\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let us add an expression to compute the cooling cost assuming a cost of 0.212E-4 $/kW. Note that cooling utility is required for the reactor (R101) and the first flash (F101). " - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.206927600Z", - "start_time": "2026-02-25T17:35:52.199682100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.229153Z", - "iopub.status.busy": "2026-02-25T17:37:01.229153Z", - "iopub.status.idle": "2026-02-25T17:37:01.232043Z", - "shell.execute_reply": "2026-02-25T17:37:01.232043Z" - } - }, - "outputs": [], - "source": [ - "m.fs.cooling_cost = Expression(\n", - " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Now, let us add an expression to compute the heating cost assuming the utility cost as follows:\n", - "
    \n", - "
  • 2.2E-4 dollars/kW for H101
  • \n", - "
  • 1.9E-4 dollars/kW for F102
  • \n", - "
\n", - "Note that the heat duty is in units of watt (J/s). " - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.213281800Z", - "start_time": "2026-02-25T17:35:52.207938700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.233055Z", - "iopub.status.busy": "2026-02-25T17:37:01.233055Z", - "iopub.status.idle": "2026-02-25T17:37:01.236107Z", - "shell.execute_reply": "2026-02-25T17:37:01.236107Z" - } - }, - "outputs": [], - "source": [ - "m.fs.heating_cost = Expression(\n", - " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us now add an expression to compute the total operating cost per year which is basically the sum of the cooling and heating cost we defined above. " - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.223516400Z", - "start_time": "2026-02-25T17:35:52.214785300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.237805Z", - "iopub.status.busy": "2026-02-25T17:37:01.237805Z", - "iopub.status.idle": "2026-02-25T17:37:01.239960Z", - "shell.execute_reply": "2026-02-25T17:37:01.239960Z" - } - }, - "outputs": [], - "source": [ - "m.fs.operating_cost = Expression(\n", - " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4 Specifying the Model\n", - "### 4.1 Fixing feed conditions\n", - "\n", - "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.255077700Z", - "start_time": "2026-02-25T17:35:52.225020600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.240972Z", - "iopub.status.busy": "2026-02-25T17:37:01.240972Z", - "iopub.status.idle": "2026-02-25T17:37:01.262642Z", - "shell.execute_reply": "2026-02-25T17:37:01.262642Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "29\n" - ] - } - ], - "source": [ - "print(degrees_of_freedom(m))" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.285702800Z", - "start_time": "2026-02-25T17:35:52.257114700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.292395Z", - "iopub.status.busy": "2026-02-25T17:37:01.292395Z", - "iopub.status.idle": "2026-02-25T17:37:01.313514Z", - "shell.execute_reply": "2026-02-25T17:37:01.313514Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# Check the degrees of freedom\n", - "assert degrees_of_freedom(m) == 29" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note\n", - "that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to\n", - "help with convergence and initializing. We will be importing a function that will specify the inlet conditions for\n", - "this example." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.318309500Z", - "start_time": "2026-02-25T17:35:52.286719600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.315025Z", - "iopub.status.busy": "2026-02-25T17:37:01.315025Z", - "iopub.status.idle": "2026-02-25T17:37:01.318666Z", - "shell.execute_reply": "2026-02-25T17:37:01.318666Z" - } - }, - "outputs": [], - "source": [ - "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", - "\n", - "tear_guesses = fix_inlet_states(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4.2 Fixing unit model specifications\n", - "\n", - "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.323682200Z", - "start_time": "2026-02-25T17:35:52.318309500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.319869Z", - "iopub.status.busy": "2026-02-25T17:37:01.319869Z", - "iopub.status.idle": "2026-02-25T17:37:01.322394Z", - "shell.execute_reply": "2026-02-25T17:37:01.322394Z" - } - }, - "outputs": [], - "source": [ - "m.fs.H101.outlet.temperature.fix(600)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For the StoichiometricReactor, we have to define the conversion in terms of toluene. This requires us to create a new variable for specifying the conversion and adding a Constraint that defines the conversion with respect to toluene. The second degree of freedom for the reactor is to define the heat duty. In this case, let us assume the reactor to be adiabatic i.e. Q = 0. " - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.330667900Z", - "start_time": "2026-02-25T17:35:52.324681600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.323406Z", - "iopub.status.busy": "2026-02-25T17:37:01.323406Z", - "iopub.status.idle": "2026-02-25T17:37:01.327204Z", - "shell.execute_reply": "2026-02-25T17:37:01.327204Z" - } - }, - "outputs": [], - "source": [ - "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", - "\n", - "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion\n", - " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", - " == (\n", - " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", - " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"toluene\"\n", - " ]\n", - " )\n", - ")\n", - "\n", - "m.fs.R101.conversion.fix(0.75)\n", - "m.fs.R101.heat_duty.fix(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The Flash conditions for F101 can be set as follows. " - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.338751Z", - "start_time": "2026-02-25T17:35:52.331676800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.328216Z", - "iopub.status.busy": "2026-02-25T17:37:01.328216Z", - "iopub.status.idle": "2026-02-25T17:37:01.331434Z", - "shell.execute_reply": "2026-02-25T17:37:01.331434Z" - } - }, - "outputs": [], - "source": [ - "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", - "m.fs.F101.deltaP.fix(0)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.344658Z", - "start_time": "2026-02-25T17:35:52.338751Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.332964Z", - "iopub.status.busy": "2026-02-25T17:37:01.332964Z", - "iopub.status.idle": "2026-02-25T17:37:01.335505Z", - "shell.execute_reply": "2026-02-25T17:37:01.335505Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "m.fs.F102.vap_outlet.temperature.fix(375)\n", - "m.fs.F102.deltaP.fix(-200000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us fix the purge split fraction to 20% and the outlet pressure of the compressor is set to 350000 Pa. " - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.352758300Z", - "start_time": "2026-02-25T17:35:52.344658Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.337180Z", - "iopub.status.busy": "2026-02-25T17:37:01.337180Z", - "iopub.status.idle": "2026-02-25T17:37:01.339352Z", - "shell.execute_reply": "2026-02-25T17:37:01.339352Z" - } - }, - "outputs": [], - "source": [ - "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", - "m.fs.C101.outlet.pressure.fix(350000)" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.381864700Z", - "start_time": "2026-02-25T17:35:52.353805400Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.340365Z", - "iopub.status.busy": "2026-02-25T17:37:01.340365Z", - "iopub.status.idle": "2026-02-25T17:37:01.361734Z", - "shell.execute_reply": "2026-02-25T17:37:01.361734Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n" - ] - } - ], - "source": [ - "print(degrees_of_freedom(m))" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.407744700Z", - "start_time": "2026-02-25T17:35:52.381864700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.363242Z", - "iopub.status.busy": "2026-02-25T17:37:01.363242Z", - "iopub.status.idle": "2026-02-25T17:37:01.384931Z", - "shell.execute_reply": "2026-02-25T17:37:01.384931Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# Check the degrees of freedom\n", - "assert degrees_of_freedom(m) == 0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5 Initializing the Model\n", - "\n", - "\n", - "\n", - "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", - "\n", - "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", - "\n", - "\n", - "![](HDA_tear_stream.png)\n", - "\n", - "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or\n", - "manually propagating through the flowsheet. The tear stream in this example will be the stream from the mixer to the heater since that is where the\n", - "recycle stream first enters back into the main process.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, we will highlight some helpful functions that are used in the initialization process." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.449167600Z", - "start_time": "2026-02-25T17:35:52.408760200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.386189Z", - "iopub.status.busy": "2026-02-25T17:37:01.386189Z", - "iopub.status.idle": "2026-02-25T17:37:01.389712Z", - "shell.execute_reply": "2026-02-25T17:37:01.389712Z" - } - }, - "outputs": [], - "source": [ - "def initialize_unit(unit):\n", - " from idaes.core.util.exceptions import InitializationError\n", - " import idaes.logger as idaeslog\n", - "\n", - " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 1000,\n", - " \"tol\": 1e-8,\n", - " }\n", - "\n", - " try:\n", - " initializer = unit.default_initializer(solver_options=optarg)\n", - " initializer.initialize(unit, output_level=idaeslog.INFO_LOW)\n", - " except InitializationError:\n", - " solver = get_solver(solver_options=optarg)\n", - " solver.solve(unit)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This first function will take any unit model and can either initialize the model with its respective default\n", - "initializer, or use a generic solver and the solve the current state of the unit model. Often times a direct\n", - "initialization method will fail while a solving method will converge so having the option for both is helpful.\n", - "\n", - "\n", - "### 5.1 Sequential Decomposition\n", - "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.456955900Z", - "start_time": "2026-02-25T17:35:52.450173700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.390724Z", - "iopub.status.busy": "2026-02-25T17:37:01.390724Z", - "iopub.status.idle": "2026-02-25T17:37:01.394398Z", - "shell.execute_reply": "2026-02-25T17:37:01.394398Z" - } - }, - "outputs": [], - "source": [ - "def automatic_propagation(m, tear_guesses):\n", - "\n", - " from pyomo.network import SequentialDecomposition\n", - "\n", - " seq = SequentialDecomposition()\n", - " seq.options.select_tear_method = \"heuristic\"\n", - " seq.options.tear_method = \"Wegstein\"\n", - " seq.options.iterLim = 5\n", - "\n", - " # Using the SD tool\n", - " G = seq.create_graph(m)\n", - " heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", - " order = seq.calculation_order(G)\n", - "\n", - " # Pass the tear_guess to the SD tool\n", - " seq.set_guesses_for(heuristic_tear_set[0].destination, tear_guesses)\n", - "\n", - " print(f\"Tear Stream starts at: {heuristic_tear_set[0].destination.name}\")\n", - "\n", - " for o in order:\n", - " print(o[0].name)\n", - "\n", - " seq.run(m, initialize_unit)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are now ready to initialize our flowsheet in a sequential mode. Note that we specifically set the iteration limit\n", - "to be 5 as we are trying to use this tool only to get a good set of initial values such that IPOPT can then take over\n", - " and solve this flowsheet for us. Uncomment this function call to run the automatic propagation method" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.462765900Z", - "start_time": "2026-02-25T17:35:52.457963700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.396187Z", - "iopub.status.busy": "2026-02-25T17:37:01.394910Z", - "iopub.status.idle": "2026-02-25T17:37:01.398217Z", - "shell.execute_reply": "2026-02-25T17:37:01.398217Z" - } - }, - "outputs": [], - "source": [ - "# automatic_propagation(m, tear_guesses)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.2 Manual Propagation Method\n", - "\n", - "This method uses a more direct approach to initialize the flowsheet, using the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", - "Lets define the function that will help us manually propagate and step through the flowsheet" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:52.472338Z", - "start_time": "2026-02-25T17:35:52.463882Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.399725Z", - "iopub.status.busy": "2026-02-25T17:37:01.399725Z", - "iopub.status.idle": "2026-02-25T17:37:01.406005Z", - "shell.execute_reply": "2026-02-25T17:37:01.406005Z" - } - }, - "outputs": [], - "source": [ - "def manual_propagation(m, tear_guesses):\n", - " from idaes.core.util.initialization import propagate_state\n", - "\n", - " print(f\"The DOF is {degrees_of_freedom(m)} initially\")\n", - " m.fs.s03_expanded.deactivate()\n", - " print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")\n", - "\n", - " for k, v in tear_guesses.items():\n", - " for k1, v1 in v.items():\n", - " getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", - "\n", - " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", - "\n", - " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 300,\n", - " # \"tol\": 1e-10,\n", - " }\n", - "\n", - " solver = get_solver(solver_options=optarg)\n", - "\n", - " initialize_unit(m.fs.H101) # Initialize Heater\n", - " propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", - " initialize_unit(m.fs.R101) # Initialize Reactor\n", - " propagate_state(\n", - " m.fs.s05\n", - " ) # Establish connection between Reactor and First Flash Unit\n", - " initialize_unit(m.fs.F101) # Initialize First Flash Unit\n", - " propagate_state(\n", - " m.fs.s06\n", - " ) # Establish connection between First Flash Unit and Splitter\n", - " propagate_state(\n", - " m.fs.s07\n", - " ) # Establish connection between First Flash Unit and Second Flash Unit\n", - " initialize_unit(m.fs.S101) # Initialize Splitter\n", - " propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", - " initialize_unit(m.fs.C101) # Initialize Compressor\n", - " propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", - " initialize_unit(m.fs.I101) # Initialize Toluene Inlet\n", - " propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", - " initialize_unit(m.fs.I102) # Initialize Hydrogen Inlet\n", - " propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", - " initialize_unit(m.fs.M101) # Initialize Mixer\n", - " propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", - " solver.solve(m.fs.F102)\n", - " propagate_state(\n", - " m.fs.s10\n", - " ) # Establish connection between Second Flash Unit and Benzene Product\n", - " propagate_state(\n", - " m.fs.s11\n", - " ) # Establish connection between Second Flash Unit and Toluene Product\n", - " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", - "\n", - " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 300,\n", - " \"tol\": 1e-8,\n", - " }\n", - " solver = get_solver(\"ipopt_v2\", options=optarg)\n", - " solver.solve(m, tee=False)\n", - "\n", - " for k, v in tear_guesses.items():\n", - " for k1, v1 in v.items():\n", - " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", - "\n", - " m.fs.s03_expanded.activate()\n", - " print(\n", - " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It will first show that the degrees of freedom is correctly at 0 before any streams are deactivated. Once the tear\n", - "stream is deactivated though, the degrees of freedom will be 10. That means 10 variables will have to be defined with\n", - " the tear guesses `tear_guesses`. Then each unit model can be initialized with our same helper function and then can\n", - " propagate the corresponding connection to the following unit models. At the end, the whole flowsheet is solved,\n", - " giving a much better chance for the recycle stream to be used correctly the flowsheet to converge." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:54.945652800Z", - "start_time": "2026-02-25T17:35:52.472338Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:01.407517Z", - "iopub.status.busy": "2026-02-25T17:37:01.407517Z", - "iopub.status.idle": "2026-02-25T17:37:03.231441Z", - "shell.execute_reply": "2026-02-25T17:37:03.231441Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The DOF is 0 initially\n", - "The DOF is 10 after deactivating the tear stream\n", - "The DOF is 0 after setting the tear stream\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The DOF is 0 after unfixing the values and reactivating the tear stream\n" - ] - } - ], - "source": [ - "manual_propagation(m, tear_guesses)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6 Solving the Model" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:54.955961300Z", - "start_time": "2026-02-25T17:35:54.948142500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.233459Z", - "iopub.status.busy": "2026-02-25T17:37:03.233459Z", - "iopub.status.idle": "2026-02-25T17:37:03.235713Z", - "shell.execute_reply": "2026-02-25T17:37:03.235713Z" - } - }, - "outputs": [], - "source": [ - "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", - " \"OF_ma57_automatic_scaling\": \"yes\",\n", - " \"max_iter\": 1000,\n", - " \"tol\": 1e-8,\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.058800400Z", - "start_time": "2026-02-25T17:35:54.955961300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.236732Z", - "iopub.status.busy": "2026-02-25T17:37:03.236732Z", - "iopub.status.idle": "2026-02-25T17:37:03.322948Z", - "shell.execute_reply": "2026-02-25T17:37:03.322948Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Create the solver object\n", - "solver = get_solver(\"ipopt_v2\", options=optarg)\n", - "\n", - "# Solve the model\n", - "results = solver.solve(m, tee=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.069069400Z", - "start_time": "2026-02-25T17:35:55.060826300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.324981Z", - "iopub.status.busy": "2026-02-25T17:37:03.324981Z", - "iopub.status.idle": "2026-02-25T17:37:03.327515Z", - "shell.execute_reply": "2026-02-25T17:37:03.327515Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# Check solver solve status\n", - "from pyomo.environ import TerminationCondition\n", - "\n", - "assert results.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7 Analyze the results\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.103403500Z", - "start_time": "2026-02-25T17:35:55.070094800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.329026Z", - "iopub.status.busy": "2026-02-25T17:37:03.329026Z", - "iopub.status.idle": "2026-02-25T17:37:03.357434Z", - "shell.execute_reply": "2026-02-25T17:37:03.357434Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Flowsheet : fs Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", - " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", - " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", - " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", - "====================================================================================\n" - ] - } - ], - "source": [ - "m.fs.report()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What is the total operating cost?" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.121297900Z", - "start_time": "2026-02-25T17:35:55.112463900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.358968Z", - "iopub.status.busy": "2026-02-25T17:37:03.358968Z", - "iopub.status.idle": "2026-02-25T17:37:03.361678Z", - "shell.execute_reply": "2026-02-25T17:37:03.361678Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "operating cost = $ 419008.28211932775\n" - ] - } - ], - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.219152500Z", - "start_time": "2026-02-25T17:35:55.130706600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.362877Z", - "iopub.status.busy": "2026-02-25T17:37:03.362877Z", - "iopub.status.idle": "2026-02-25T17:37:03.450520Z", - "shell.execute_reply": "2026-02-25T17:37:03.450001Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "import pytest\n", - "\n", - "assert value(m.fs.operating_cost) == pytest.approx(419008.28189, abs=1e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.236354800Z", - "start_time": "2026-02-25T17:35:55.221348800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.451538Z", - "iopub.status.busy": "2026-02-25T17:37:03.451538Z", - "iopub.status.idle": "2026-02-25T17:37:03.463598Z", - "shell.execute_reply": "2026-02-25T17:37:03.463598Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Unit : fs.F102 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : 7346.7 : watt : False : (None, None)\n", - " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", - "====================================================================================\n", - "\n", - "benzene purity = 0.8242963521555953\n" - ] - } - ], - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.252635700Z", - "start_time": "2026-02-25T17:35:55.245056800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.465105Z", - "iopub.status.busy": "2026-02-25T17:37:03.465105Z", - "iopub.status.idle": "2026-02-25T17:37:03.468162Z", - "shell.execute_reply": "2026-02-25T17:37:03.468162Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3)\n", - "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.266766800Z", - "start_time": "2026-02-25T17:35:55.254139200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.468666Z", - "iopub.status.busy": "2026-02-25T17:37:03.468666Z", - "iopub.status.idle": "2026-02-25T17:37:03.477176Z", - "shell.execute_reply": "2026-02-25T17:37:03.477176Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", - "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", - "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", - "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", - "Total Mole Fraction ('Vap', 'benzene') dimensionless 0.17408 0.084499 \n", - "Total Mole Fraction ('Vap', 'toluene') dimensionless 0.038450 0.0088437 \n", - "Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.16148 0.18592 \n", - "Total Mole Fraction ('Vap', 'methane') dimensionless 0.62599 0.72074 \n", - "Temperature kelvin 771.86 325.00 \n", - "Pressure pascal 3.5000e+05 3.5000e+05 \n" - ] - } - ], - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 8 Optimization\n", - "\n", - "\n", - "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", - "\n", - "Let us try to minimize this cost such that:\n", - "- we are producing at least 0.15 mol/s of benzene in F102 vapor outlet i.e. our product stream\n", - "- purity of benzene i.e. the mole fraction of benzene in F102 vapor outlet is at least 80%\n", - "- restricting the benzene loss in F101 vapor outlet to less than 20%\n", - "\n", - "For this problem, our decision variables are as follows:\n", - "- H101 outlet temperature\n", - "- R101 cooling duty provided\n", - "- F101 outlet temperature\n", - "- F102 outlet temperature\n", - "- F102 deltaP in the flash tank\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us declare our objective function for this problem. " - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.282509700Z", - "start_time": "2026-02-25T17:35:55.274959700Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.478398Z", - "iopub.status.busy": "2026-02-25T17:37:03.478398Z", - "iopub.status.idle": "2026-02-25T17:37:03.481973Z", - "shell.execute_reply": "2026-02-25T17:37:03.481469Z" - } - }, - "outputs": [], - "source": [ - "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we need to unfix the decision variables as we had solved a square problem (degrees of freedom = 0) until now.\n", - "\n", - "Because we are using a stoichiometric reactor, the reactor temperature has no effect on the reaction yield. Additionally, we are using the same cost for heat removal from both the reactor and flash units. Therefore, the optimization algorithm has no reason to prefer heat removal in one place or the other; the solution returned is not locally unique. To remove this indeterminancy and ensure that a consistent solution is returned, we fix the outlet temperature of the reactor." - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.290823900Z", - "start_time": "2026-02-25T17:35:55.283519100Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.482978Z", - "iopub.status.busy": "2026-02-25T17:37:03.482978Z", - "iopub.status.idle": "2026-02-25T17:37:03.486295Z", - "shell.execute_reply": "2026-02-25T17:37:03.486295Z" - } - }, - "outputs": [], - "source": [ - "m.fs.H101.outlet.temperature.unfix()\n", - "m.fs.R101.heat_duty.unfix()\n", - "m.fs.R101.outlet.temperature.fix(600)\n", - "m.fs.F101.vap_outlet.temperature.unfix()\n", - "m.fs.F102.vap_outlet.temperature.unfix()" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.298239900Z", - "start_time": "2026-02-25T17:35:55.290823900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.487812Z", - "iopub.status.busy": "2026-02-25T17:37:03.487812Z", - "iopub.status.idle": "2026-02-25T17:37:03.490322Z", - "shell.execute_reply": "2026-02-25T17:37:03.490322Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Unfix deltaP for F102\n", - "m.fs.F102.deltaP.unfix()" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.326558700Z", - "start_time": "2026-02-25T17:35:55.298239900Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.492343Z", - "iopub.status.busy": "2026-02-25T17:37:03.491337Z", - "iopub.status.idle": "2026-02-25T17:37:03.512926Z", - "shell.execute_reply": "2026-02-25T17:37:03.512926Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "assert degrees_of_freedom(m) == 4" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we need to set bounds on these decision variables to values shown below:\n", - "\n", - " - H101 outlet temperature [500, 600] K\n", - " - F101 outlet temperature [298, 450] K\n", - " - F102 outlet temperature [298, 450] K\n", - " - F102 outlet pressure [105000, 110000] Pa\n", - "\n", - "Let us first set the variable bound for the H101 outlet temperature as shown below:" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.335276900Z", - "start_time": "2026-02-25T17:35:55.329070200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.514448Z", - "iopub.status.busy": "2026-02-25T17:37:03.514448Z", - "iopub.status.idle": "2026-02-25T17:37:03.516812Z", - "shell.execute_reply": "2026-02-25T17:37:03.516812Z" - } - }, - "outputs": [], - "source": [ - "m.fs.H101.outlet.temperature[0].setlb(500)\n", - "m.fs.H101.outlet.temperature[0].setub(600)" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.343371700Z", - "start_time": "2026-02-25T17:35:55.336287300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.517823Z", - "iopub.status.busy": "2026-02-25T17:37:03.517823Z", - "iopub.status.idle": "2026-02-25T17:37:03.520860Z", - "shell.execute_reply": "2026-02-25T17:37:03.520860Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Set the bounds for reactor outlet temperature\n", - "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", - "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us fix the bounds for the rest of the decision variables. " - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.352423500Z", - "start_time": "2026-02-25T17:35:55.344876400Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.521874Z", - "iopub.status.busy": "2026-02-25T17:37:03.521874Z", - "iopub.status.idle": "2026-02-25T17:37:03.525414Z", - "shell.execute_reply": "2026-02-25T17:37:03.525414Z" - } - }, - "outputs": [], - "source": [ - "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", - "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", - "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", - "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, the only things left to define are our constraints on overhead loss in F101, product flow rate and purity in F102. Let us first look at defining a constraint for the overhead loss in F101 where we are restricting the benzene leaving the vapor stream to less than 20 \\% of the benzene available in the reactor outlet. " - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.360963300Z", - "start_time": "2026-02-25T17:35:55.353445300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.526425Z", - "iopub.status.busy": "2026-02-25T17:37:03.526425Z", - "iopub.status.idle": "2026-02-25T17:37:03.529414Z", - "shell.execute_reply": "2026-02-25T17:37:03.529414Z" - } - }, - "outputs": [], - "source": [ - "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"benzene\"\n", - " ]\n", - " <= 0.20\n", - " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.369058600Z", - "start_time": "2026-02-25T17:35:55.360963300Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.530926Z", - "iopub.status.busy": "2026-02-25T17:37:03.530926Z", - "iopub.status.idle": "2026-02-25T17:37:03.533250Z", - "shell.execute_reply": "2026-02-25T17:37:03.533250Z" - }, - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Add minimum product flow constraint\n", - "m.fs.product_flow = Constraint(\n", - " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", - " \"Vap\", \"benzene\"\n", - " ]\n", - " >= 0.15\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us add the final constraint on product purity or the mole fraction of benzene in the product stream such that it is at least greater than 80%. " - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.376320300Z", - "start_time": "2026-02-25T17:35:55.369058600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.534770Z", - "iopub.status.busy": "2026-02-25T17:37:03.534770Z", - "iopub.status.idle": "2026-02-25T17:37:03.537111Z", - "shell.execute_reply": "2026-02-25T17:37:03.537111Z" - } - }, - "outputs": [], - "source": [ - "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "We have now defined the optimization problem and we are now ready to solve this problem. \n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.492529900Z", - "start_time": "2026-02-25T17:35:55.377335800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.538124Z", - "iopub.status.busy": "2026-02-25T17:37:03.538124Z", - "iopub.status.idle": "2026-02-25T17:37:03.640087Z", - "shell.execute_reply": "2026-02-25T17:37:03.640087Z" - } - }, - "outputs": [], - "source": [ - "results = solver.solve(m, tee=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.502156500Z", - "start_time": "2026-02-25T17:35:55.495039800Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.642111Z", - "iopub.status.busy": "2026-02-25T17:37:03.642111Z", - "iopub.status.idle": "2026-02-25T17:37:03.644659Z", - "shell.execute_reply": "2026-02-25T17:37:03.644659Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "# Check for solver solve status\n", - "from pyomo.environ import TerminationCondition\n", - "\n", - "assert results.solver.termination_condition == TerminationCondition.optimal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 8.1 Optimization Results\n", - "\n", - "Display the results and product specifications" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.547787400Z", - "start_time": "2026-02-25T17:35:55.502662600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.645676Z", - "iopub.status.busy": "2026-02-25T17:37:03.645676Z", - "iopub.status.idle": "2026-02-25T17:37:03.665720Z", - "shell.execute_reply": "2026-02-25T17:37:03.665720Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "operating cost = $ 312674.2367538264\n", - "\n", - "Product flow rate and purity in F102\n", - "\n", - "====================================================================================\n", - "Unit : fs.F102 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : 8370.2 : watt : False : (None, None)\n", - " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", - "====================================================================================\n", - "\n", - "benzene purity = 0.818829588839798\n", - "\n", - "Overhead loss in F101\n", - "\n", - "====================================================================================\n", - "Unit : fs.F101 Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : -42942. : watt : False : (None, None)\n", - " Pressure Change : 0.0000 : pascal : True : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", - "====================================================================================\n" - ] - } - ], - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.568590500Z", - "start_time": "2026-02-25T17:35:55.550822200Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.666733Z", - "iopub.status.busy": "2026-02-25T17:37:03.666733Z", - "iopub.status.idle": "2026-02-25T17:37:03.670271Z", - "shell.execute_reply": "2026-02-25T17:37:03.670271Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "assert value(m.fs.operating_cost) == pytest.approx(312674.236, abs=1e-3)\n", - "assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display optimal values for the decision variables" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.609020800Z", - "start_time": "2026-02-25T17:35:55.580082500Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.671295Z", - "iopub.status.busy": "2026-02-25T17:37:03.671295Z", - "iopub.status.idle": "2026-02-25T17:37:03.675724Z", - "shell.execute_reply": "2026-02-25T17:37:03.675724Z" + "cells": [ + { + "cell_type": "code", + "metadata": { + "tags": [ + "header", + "hide-cell" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:01.286374300Z", + "start_time": "2026-02-25T17:35:01.274737700Z" + } + }, + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2026 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ], + "outputs": [], + "execution_count": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# HDA Flowsheet Simulation and Optimization\n", + "\n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2026-1-12\n", + "\n", + "## Learning outcomes\n", + "\n", + "\n", + "- Construct a steady-state flowsheet using the IDAES unit model library\n", + "- Connecting unit models in a flowsheet using Arcs\n", + "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", + "- Formulate and solve an optimization problem\n", + " - Defining an objective function\n", + " - Setting variable bounds\n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", + "     8 Optimizing the Model
\n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", + "\n", + "\n", + "## Problem Statement\n", + "\n", + "Hydrodealkylation is a chemical reaction that often involves reacting\n", + "an aromatic hydrocarbon in the presence of hydrogen gas to form a\n", + "simpler aromatic hydrocarbon devoid of functional groups. In this\n", + "example, toluene will be reacted with hydrogen gas at high temperatures\n", + " to form benzene via the following reaction:\n", + "\n", + "**C6H5CH3 + H2 \u2192 C6H6 + CH4**\n", + "\n", + "\n", + "This reaction is often accompanied by an equilibrium side reaction\n", + "which forms diphenyl, which we will neglect for this example.\n", + "\n", + "This example is based on the 1967 AIChE Student Contest problem as\n", + "present by Douglas, J.M., Chemical Design of Chemical Processes, 1988,\n", + "McGraw-Hill.\n", + "\n", + "The flowsheet that we will be using for this module is shown below with the stream conditions. We will be processing toluene and hydrogen to produce at least 370 TPY of benzene. As shown in the flowsheet, there are two flash tanks, F101 to separate out the non-condensibles and F102 to further separate the benzene-toluene mixture to improve the benzene purity. Note that typically a distillation column is required to obtain high purity benzene but that is beyond the scope of this workshop. The non-condensibles separated out in F101 will be partially recycled back to M101 and the rest will be either purged or combusted for power generation.We will assume ideal gas for this flowsheet. The properties required for this module are available in the same directory:\n", + "\n", + "- hda_ideal_VLE.py\n", + "- hda_reaction.py\n", + "\n", + "The state variables chosen for the property package are **flows of component by phase, temperature and pressure**. The components considered are: **toluene, hydrogen, benzene and methane**. Therefore, every stream has 8 flow variables, 1 temperature and 1 pressure variable. \n", + "\n", + "![](HDA_flowsheet.png)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", + "\n", + "\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", + "- Constraint (to write constraints)\n", + "- Var (to declare variables)\n", + "- ConcreteModel (to create the concrete model object)\n", + "- Expression (to evaluate values as a function of variables defined in the model)\n", + "- Objective (to define an objective function for optimization)\n", + "- SolverFactory (to solve the problem)\n", + "- TransformationFactory (to apply certain transformations)\n", + "- Arc (to connect two unit models)\n", + "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", + "\n", + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:01.830457200Z", + "start_time": "2026-02-25T17:35:01.290402400Z" + } + }, + "source": [ + "from pyomo.environ import (\n", + " Constraint,\n", + " Var,\n", + " ConcreteModel,\n", + " Expression,\n", + " Objective,\n", + " TransformationFactory,\n", + " value,\n", + ")\n", + "from pyomo.network import Arc" + ], + "outputs": [], + "execution_count": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", + "- Mixer\n", + "- Heater\n", + "- StoichiometricReactor\n", + "- **Flash**\n", + "- Separator (splitter) \n", + "- PressureChanger\n", + "- Product" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.665835Z", + "start_time": "2026-02-25T17:35:01.832975100Z" + } + }, + "source": "from idaes.core import FlowsheetBlock", + "outputs": [], + "execution_count": 3 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.734656600Z", + "start_time": "2026-02-25T17:35:03.667871Z" + } + }, + "source": [ + "from idaes.models.unit_models import (\n", + " PressureChanger,\n", + " Mixer,\n", + " Separator as Splitter,\n", + " Heater,\n", + " StoichiometricReactor,\n", + " Feed,\n", + " Product,\n", + ")" + ], + "outputs": [], + "execution_count": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "Inline Exercise:\n", + "Now, import the remaining unit models highlighted in blue above and run the cell using `Shift+Enter` after typing in the code. \n", + "
\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.752580Z", + "start_time": "2026-02-25T17:35:03.745137800Z" + } + }, + "source": [ + "# Todo: import flash model from idaes.models.unit_models\n", + "from idaes.models.unit_models import Flash" + ], + "outputs": [], + "execution_count": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will also be needing some utility tools to put together the flowsheet and calculate the degrees of freedom. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.761528300Z", + "start_time": "2026-02-25T17:35:03.753588300Z" + } + }, + "source": [ + "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "\n", + "# Import idaes logger to set output levels\n", + "from idaes.core.solvers import get_solver" + ], + "outputs": [], + "execution_count": 7 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2 Importing required thermo and reaction package\n", + "\n", + "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", + "\n", + "The reaction package here is very simple as we will be using only a StochiometricReactor and the reaction package consists of the stochiometric coefficients for the reaction and the parameter for the heat of reaction. \n", + "\n", + "Let us import the following modules and they are in the same directory as this jupyter notebook:\n", + "
    \n", + "
  • hda_ideal_VLE as thermo_props
  • \n", + "
  • hda_reaction as reaction_props
  • \n", + "
\n", + "" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.838559500Z", + "start_time": "2026-02-25T17:35:03.761528300Z" + } + }, + "cell_type": "code", + "source": [ + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" + ], + "outputs": [], + "execution_count": 8 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2 Constructing the Flowsheet\n", + "\n", + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.849781Z", + "start_time": "2026-02-25T17:35:03.841636100Z" + } + }, + "source": [ + "m = ConcreteModel()\n", + "m.fs = FlowsheetBlock(dynamic=False)" + ], + "outputs": [], + "execution_count": 9 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now need to add the property packages to the flowsheet. Unlike Module 1, where we only had a thermo property package, for this flowsheet we will also need to add a reaction property package. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.879447Z", + "start_time": "2026-02-25T17:35:03.851130600Z" + } + }, + "source": [ + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", + ")" + ], + "outputs": [], + "execution_count": 10 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.1 Adding Unit Models\n", + "\n", + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.925685100Z", + "start_time": "2026-02-25T17:35:03.881771100Z" + } + }, + "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.M101 = Mixer(\n", + " property_package=m.fs.thermo_params,\n", + " num_inlets=3,\n", + ")\n", + "\n", + "m.fs.H101 = Heater(\n", + " property_package=m.fs.thermo_params,\n", + " has_pressure_change=False,\n", + " has_phase_equilibrium=True,\n", + ")" + ], + "outputs": [], + "execution_count": 11 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.956022500Z", + "start_time": "2026-02-25T17:35:03.935614400Z" + } + }, + "source": [ + "# Todo: Add reactor with the specifications above\n", + "m.fs.R101 = StoichiometricReactor(\n", + " property_package=m.fs.thermo_params,\n", + " reaction_package=m.fs.reaction_params,\n", + " has_heat_of_reaction=True,\n", + " has_heat_transfer=True,\n", + " has_pressure_change=False,\n", + ")" + ], + "outputs": [], + "execution_count": 13 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now add the Flash(assign the name F101) and pass the following arguments:\n", + "
    \n", + "
  • \"property_package\": m.fs.thermo_params
  • \n", + "
  • \"has_heat_transfer\": True
  • \n", + "
  • \"has_pressure_change\": False
  • \n", + "
" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:03.979104400Z", + "start_time": "2026-02-25T17:35:03.958076200Z" + } + }, + "source": [ + "m.fs.F101 = Flash(\n", + " property_package=m.fs.thermo_params,\n", + " has_heat_transfer=True,\n", + " has_pressure_change=True,\n", + ")" + ], + "outputs": [], + "execution_count": 14 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.031371300Z", + "start_time": "2026-02-25T17:35:03.981638100Z" + } + }, + "source": [ + "m.fs.S101 = Splitter(\n", + " property_package=m.fs.thermo_params,\n", + " ideal_separation=False,\n", + " outlet_list=[\"purge\", \"recycle\"],\n", + ")\n", + "\n", + "\n", + "m.fs.C101 = PressureChanger(\n", + " property_package=m.fs.thermo_params,\n", + " compressor=True,\n", + " thermodynamic_assumption=ThermodynamicAssumption.isothermal,\n", + ")\n", + "\n", + "m.fs.F102 = Flash(\n", + " property_package=m.fs.thermo_params,\n", + " has_heat_transfer=True,\n", + " has_pressure_change=True,\n", + ")" + ], + "outputs": [], + "execution_count": 15 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.049278900Z", + "start_time": "2026-02-25T17:35:04.033910400Z" + } + }, + "source": [ + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" + ], + "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.2 Connecting Unit Models using Arcs\n", + "\n", + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](HDA_flowsheet.png)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.059097Z", + "start_time": "2026-02-25T17:35:04.051649500Z" + } + }, + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.074873700Z", + "start_time": "2026-02-25T17:35:04.067198800Z" + } + }, + "source": [ + "# Todo: Connect the H101 outlet to R101 inlet\n", + "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" + ], + "outputs": [], + "execution_count": 19 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will now be connecting the rest of the flowsheet as shown below. Notice how the outlet names are different for the flash tanks F101 and F102 as they have a vapor and a liquid outlet. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.082717500Z", + "start_time": "2026-02-25T17:35:04.075379Z" + } + }, + "source": [ + "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", + "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", + "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" + ], + "outputs": [], + "execution_count": 20 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.091461Z", + "start_time": "2026-02-25T17:35:04.083716700Z" + } + }, + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ], + "outputs": [], + "execution_count": 21 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows:" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.116142500Z", + "start_time": "2026-02-25T17:35:04.092591700Z" + } + }, + "source": [ + "TransformationFactory(\"network.expand_arcs\").apply_to(m)" + ], + "outputs": [], + "execution_count": 22 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.3 Adding expressions to compute purity and operating costs\n", + "\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", + "\n", + "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us first add an Expression to compute the mole fraction of benzene in the `vap_outlet` of F102 which is our product stream. Please note that the var flow_mol_phase_comp has the index - [time, phase, component]. As this is a steady-state flowsheet, the time index by default is 0. The valid phases are [\"Liq\", \"Vap\"]. Similarly the valid component list is [\"benzene\", \"toluene\", \"hydrogen\", \"methane\"]." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.126991900Z", + "start_time": "2026-02-25T17:35:04.118294Z" + } + }, + "source": [ + "m.fs.purity = Expression(\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " / (\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", + " )\n", + ")" + ], + "outputs": [], + "execution_count": 23 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let us add an expression to compute the cooling cost assuming a cost of 0.212E-4 $/kW. Note that cooling utility is required for the reactor (R101) and the first flash (F101). " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.134981600Z", + "start_time": "2026-02-25T17:35:04.126991900Z" + } + }, + "source": [ + "m.fs.cooling_cost = Expression(\n", + " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", + ")" + ], + "outputs": [], + "execution_count": 24 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Now, let us add an expression to compute the heating cost assuming the utility cost as follows:\n", + "
    \n", + "
  • 2.2E-4 dollars/kW for H101
  • \n", + "
  • 1.9E-4 dollars/kW for F102
  • \n", + "
\n", + "Note that the heat duty is in units of watt (J/s). " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.142918500Z", + "start_time": "2026-02-25T17:35:04.134981600Z" + } + }, + "source": [ + "m.fs.heating_cost = Expression(\n", + " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", + ")" + ], + "outputs": [], + "execution_count": 25 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us now add an expression to compute the total operating cost per year which is basically the sum of the cooling and heating cost we defined above. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.151633300Z", + "start_time": "2026-02-25T17:35:04.143918400Z" + } + }, + "source": [ + "m.fs.operating_cost = Expression(\n", + " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", + ")" + ], + "outputs": [], + "execution_count": 26 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", + "\n", + "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.183600800Z", + "start_time": "2026-02-25T17:35:04.152655800Z" + } + }, + "source": [ + "print(degrees_of_freedom(m))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], + "execution_count": 27 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.216388800Z", + "start_time": "2026-02-25T17:35:04.187853900Z" + } + }, + "source": [ + "# Check the degrees of freedom\n", + "assert degrees_of_freedom(m) == 29" + ], + "outputs": [], + "execution_count": 28 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note\n", + "that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to\n", + "help with convergence and initializing. We will be importing a function that will specify the inlet conditions for\n", + "this example." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.227743300Z", + "start_time": "2026-02-25T17:35:04.218810900Z" + } + }, + "source": [ + "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", + "\n", + "tear_guesses = fix_inlet_states(m)" + ], + "outputs": [], + "execution_count": 29 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2 Fixing unit model specifications\n", + "\n", + "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.235882200Z", + "start_time": "2026-02-25T17:35:04.227743300Z" + } + }, + "source": [ + "m.fs.H101.outlet.temperature.fix(600)" + ], + "outputs": [], + "execution_count": 30 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the StoichiometricReactor, we have to define the conversion in terms of toluene. This requires us to create a new variable for specifying the conversion and adding a Constraint that defines the conversion with respect to toluene. The second degree of freedom for the reactor is to define the heat duty. In this case, let us assume the reactor to be adiabatic i.e. Q = 0. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.257770300Z", + "start_time": "2026-02-25T17:35:04.236888500Z" + } + }, + "source": [ + "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", + "\n", + "m.fs.R101.conv_constraint = Constraint(\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", + " == (\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", + " )\n", + ")\n", + "\n", + "m.fs.R101.conversion.fix(0.75)\n", + "m.fs.R101.heat_duty.fix(0)" + ], + "outputs": [], + "execution_count": 31 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Flash conditions for F101 can be set as follows. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.268846Z", + "start_time": "2026-02-25T17:35:04.260299600Z" + } + }, + "source": [ + "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", + "m.fs.F101.deltaP.fix(0)" + ], + "outputs": [], + "execution_count": 32 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.288481300Z", + "start_time": "2026-02-25T17:35:04.279196300Z" + } + }, + "source": [ + "m.fs.F102.vap_outlet.temperature.fix(375)\n", + "m.fs.F102.deltaP.fix(-200000)" + ], + "outputs": [], + "execution_count": 34 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us fix the purge split fraction to 20% and the outlet pressure of the compressor is set to 350000 Pa. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.302496300Z", + "start_time": "2026-02-25T17:35:04.289482700Z" + } + }, + "source": [ + "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", + "m.fs.C101.outlet.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 35 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.340811100Z", + "start_time": "2026-02-25T17:35:04.313761800Z" + } + }, + "source": [ + "print(degrees_of_freedom(m))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "execution_count": 37 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.374728400Z", + "start_time": "2026-02-25T17:35:04.345879200Z" + } + }, + "source": [ + "# Check the degrees of freedom\n", + "assert degrees_of_freedom(m) == 0" + ], + "outputs": [], + "execution_count": 38 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5 Initializing the Model\n", + "\n", + "\n", + "\n", + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear\u2010stream method is necessary because it \u201cbreaks\u201d this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization\u2014and ultimately steady\u2010state convergence\u2014impossible.\n", + "\n", + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", + "\n", + "\n", + "![](HDA_tear_stream.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or\n", + "manually propagating through the flowsheet. The tear stream in this example will be the stream from the mixer to the heater since that is where the\n", + "recycle stream first enters back into the main process.\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "First, we will highlight some helpful functions that are used in the initialization process." + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.386344500Z", + "start_time": "2026-02-25T17:35:04.376804600Z" + } + }, + "cell_type": "code", + "source": [ + "def initialize_unit(unit):\n", + " from idaes.core.util.exceptions import InitializationError\n", + " import idaes.logger as idaeslog\n", + "\n", + " optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + " }\n", + "\n", + " try:\n", + " initializer = unit.default_initializer(solver_options=optarg)\n", + " initializer.initialize(unit, output_level=idaeslog.INFO_LOW)\n", + " except InitializationError:\n", + " solver = get_solver(solver_options=optarg)\n", + " solver.solve(unit)" + ], + "outputs": [], + "execution_count": 39 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This first function will take any unit model and can either initialize the model with its respective default\n", + "initializer, or use a generic solver and the solve the current state of the unit model. Often times a direct\n", + "initialization method will fail while a solving method will converge so having the option for both is helpful.\n", + "\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.394802500Z", + "start_time": "2026-02-25T17:35:04.386344500Z" + } + }, + "cell_type": "code", + "source": [ + "def automatic_propagation(m, tear_guesses):\n", + "\n", + " from pyomo.network import SequentialDecomposition\n", + "\n", + " seq = SequentialDecomposition()\n", + " seq.options.select_tear_method = \"heuristic\"\n", + " seq.options.tear_method = \"Wegstein\"\n", + " seq.options.iterLim = 5\n", + "\n", + " # Using the SD tool\n", + " G = seq.create_graph(m)\n", + " heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", + " order = seq.calculation_order(G)\n", + "\n", + " # Pass the tear_guess to the SD tool\n", + " seq.set_guesses_for(heuristic_tear_set[0].destination, tear_guesses)\n", + "\n", + " print(f\"Tear Stream starts at: {heuristic_tear_set[0].destination.name}\")\n", + "\n", + " for o in order:\n", + " print(o[0].name)\n", + "\n", + " seq.run(m, initialize_unit)" + ], + "outputs": [], + "execution_count": 40 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We are now ready to initialize our flowsheet in a sequential mode. Note that we specifically set the iteration limit\n", + "to be 5 as we are trying to use this tool only to get a good set of initial values such that IPOPT can then take over\n", + " and solve this flowsheet for us. Uncomment this function call to run the automatic propagation method" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.404491500Z", + "start_time": "2026-02-25T17:35:04.396317500Z" + } + }, + "cell_type": "code", + "source": "# automatic_propagation(m, tear_guesses)", + "outputs": [], + "execution_count": 41 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, using the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets define the function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:04.417815100Z", + "start_time": "2026-02-25T17:35:04.404995800Z" + } + }, + "source": [ + "def manual_propagation(m, tear_guesses):\n", + " from idaes.core.util.initialization import propagate_state\n", + "\n", + " print(f\"The DOF is {degrees_of_freedom(m)} initially\")\n", + " m.fs.s03_expanded.deactivate()\n", + " print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")\n", + "\n", + " for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "\n", + " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", + "\n", + " optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " # \"tol\": 1e-10,\n", + " }\n", + "\n", + " solver = get_solver(solver_options=optarg)\n", + "\n", + " initialize_unit(m.fs.H101) # Initialize Heater\n", + " propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + " initialize_unit(m.fs.R101) # Initialize Reactor\n", + " propagate_state(\n", + " m.fs.s05\n", + " ) # Establish connection between Reactor and First Flash Unit\n", + " initialize_unit(m.fs.F101) # Initialize First Flash Unit\n", + " propagate_state(\n", + " m.fs.s06\n", + " ) # Establish connection between First Flash Unit and Splitter\n", + " propagate_state(\n", + " m.fs.s07\n", + " ) # Establish connection between First Flash Unit and Second Flash Unit\n", + " initialize_unit(m.fs.S101) # Initialize Splitter\n", + " propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + " initialize_unit(m.fs.C101) # Initialize Compressor\n", + " propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + " initialize_unit(m.fs.I101) # Initialize Toluene Inlet\n", + " propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + " initialize_unit(m.fs.I102) # Initialize Hydrogen Inlet\n", + " propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + " initialize_unit(m.fs.M101) # Initialize Mixer\n", + " propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + " solver.solve(m.fs.F102)\n", + " propagate_state(\n", + " m.fs.s10\n", + " ) # Establish connection between Second Flash Unit and Benzene Product\n", + " propagate_state(\n", + " m.fs.s11\n", + " ) # Establish connection between Second Flash Unit and Toluene Product\n", + " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", + "\n", + " optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + " }\n", + " solver = get_solver(\"ipopt_v2\", options=optarg)\n", + " solver.solve(m, tee=False)\n", + "\n", + " for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", + "\n", + " m.fs.s03_expanded.activate()\n", + " print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + " )" + ], + "outputs": [], + "execution_count": 42 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It will first show that the degrees of freedom is correctly at 0 before any streams are deactivated. Once the tear\n", + "stream is deactivated though, the degrees of freedom will be 10. That means 10 variables will have to be defined with\n", + " the tear guesses `tear_guesses`. Then each unit model can be initialized with our same helper function and then can\n", + " propagate the corresponding connection to the following unit models. At the end, the whole flowsheet is solved,\n", + " giving a much better chance for the recycle stream to be used correctly the flowsheet to converge." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.145125500Z", + "start_time": "2026-02-25T17:35:04.419335500Z" + } + }, + "source": "manual_propagation(m, tear_guesses)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 initially\n", + "The DOF is 10 after deactivating the tear stream\n", + "The DOF is 0 after setting the tear stream\n", + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "execution_count": 43 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.161129400Z", + "start_time": "2026-02-25T17:35:07.146644300Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ], + "outputs": [], + "execution_count": 44 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.272798500Z", + "start_time": "2026-02-25T17:35:07.170980400Z" + } + }, + "source": [ + "# Create the solver object\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "\n", + "# Solve the model\n", + "results = solver.solve(m, tee=False)" + ], + "outputs": [], + "execution_count": 46 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.281939700Z", + "start_time": "2026-02-25T17:35:07.274820400Z" + } + }, + "source": [ + "# Check solver solve status\n", + "from pyomo.environ import TerminationCondition\n", + "\n", + "assert results.solver.termination_condition == TerminationCondition.optimal" + ], + "outputs": [], + "execution_count": 47 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7 Analyze the results\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.337983600Z", + "start_time": "2026-02-25T17:35:07.303479400Z" + } + }, + "source": [ + "m.fs.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "execution_count": 49 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What is the total operating cost?" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.355013500Z", + "start_time": "2026-02-25T17:35:07.346055600Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 419008.28211932775\n" + ] + } + ], + "execution_count": 50 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.449306200Z", + "start_time": "2026-02-25T17:35:07.358159700Z" + } + }, + "source": [ + "import pytest\n", + "\n", + "assert value(m.fs.operating_cost) == pytest.approx(419008.28189, abs=1e-3)" + ], + "outputs": [], + "execution_count": 51 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.469810Z", + "start_time": "2026-02-25T17:35:07.452663800Z" + } + }, + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 7346.7 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 0.26712 - - \n", + " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8242963521555953\n" + ] + } + ], + "execution_count": 52 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.486974600Z", + "start_time": "2026-02-25T17:35:07.477988200Z" + } + }, + "source": [ + "assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3)\n", + "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, abs=1e-3)\n", + "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3)" + ], + "outputs": [], + "execution_count": 53 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.503351300Z", + "start_time": "2026-02-25T17:35:07.487979400Z" + } + }, + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", + "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", + "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", + "Total Mole Fraction ('Vap', 'benzene') dimensionless 0.17408 0.084499 \n", + "Total Mole Fraction ('Vap', 'toluene') dimensionless 0.038450 0.0088437 \n", + "Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.16148 0.18592 \n", + "Total Mole Fraction ('Vap', 'methane') dimensionless 0.62599 0.72074 \n", + "Temperature kelvin 771.86 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], + "execution_count": 54 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8 Optimization\n", + "\n", + "\n", + "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", + "\n", + "Let us try to minimize this cost such that:\n", + "- we are producing at least 0.15 mol/s of benzene in F102 vapor outlet i.e. our product stream\n", + "- purity of benzene i.e. the mole fraction of benzene in F102 vapor outlet is at least 80%\n", + "- restricting the benzene loss in F101 vapor outlet to less than 20%\n", + "\n", + "For this problem, our decision variables are as follows:\n", + "- H101 outlet temperature\n", + "- R101 cooling duty provided\n", + "- F101 outlet temperature\n", + "- F102 outlet temperature\n", + "- F102 deltaP in the flash tank\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us declare our objective function for this problem. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.523495700Z", + "start_time": "2026-02-25T17:35:07.513232100Z" + } + }, + "source": [ + "m.fs.objective = Objective(expr=m.fs.operating_cost)" + ], + "outputs": [], + "execution_count": 55 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we need to unfix the decision variables as we had solved a square problem (degrees of freedom = 0) until now.\n", + "\n", + "Because we are using a stoichiometric reactor, the reactor temperature has no effect on the reaction yield. Additionally, we are using the same cost for heat removal from both the reactor and flash units. Therefore, the optimization algorithm has no reason to prefer heat removal in one place or the other; the solution returned is not locally unique. To remove this indeterminancy and ensure that a consistent solution is returned, we fix the outlet temperature of the reactor." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.538051100Z", + "start_time": "2026-02-25T17:35:07.528058900Z" + } + }, + "source": [ + "m.fs.H101.outlet.temperature.unfix()\n", + "m.fs.R101.heat_duty.unfix()\n", + "m.fs.R101.outlet.temperature.fix(600)\n", + "m.fs.F101.vap_outlet.temperature.unfix()\n", + "m.fs.F102.vap_outlet.temperature.unfix()" + ], + "outputs": [], + "execution_count": 56 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.578318700Z", + "start_time": "2026-02-25T17:35:07.571295800Z" + } + }, + "source": [ + "# Todo: Unfix deltaP for F102\n", + "m.fs.F102.deltaP.unfix()" + ], + "outputs": [], + "execution_count": 58 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.616492Z", + "start_time": "2026-02-25T17:35:07.581710400Z" + } + }, + "source": "assert degrees_of_freedom(m) == 4", + "outputs": [], + "execution_count": 59 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we need to set bounds on these decision variables to values shown below:\n", + "\n", + " - H101 outlet temperature [500, 600] K\n", + " - F101 outlet temperature [298, 450] K\n", + " - F102 outlet temperature [298, 450] K\n", + " - F102 outlet pressure [105000, 110000] Pa\n", + "\n", + "Let us first set the variable bound for the H101 outlet temperature as shown below:" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.627054600Z", + "start_time": "2026-02-25T17:35:07.619525700Z" + } + }, + "source": [ + "m.fs.H101.outlet.temperature[0].setlb(500)\n", + "m.fs.H101.outlet.temperature[0].setub(600)" + ], + "outputs": [], + "execution_count": 60 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.652892600Z", + "start_time": "2026-02-25T17:35:07.643756900Z" + } + }, + "source": [ + "# Todo: Set the bounds for reactor outlet temperature\n", + "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", + "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" + ], + "outputs": [], + "execution_count": 62 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us fix the bounds for the rest of the decision variables. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.662831700Z", + "start_time": "2026-02-25T17:35:07.654919400Z" + } + }, + "source": [ + "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", + "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", + "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", + "m.fs.F102.vap_outlet.pressure[0].setub(110000)" + ], + "outputs": [], + "execution_count": 63 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, the only things left to define are our constraints on overhead loss in F101, product flow rate and purity in F102. Let us first look at defining a constraint for the overhead loss in F101 where we are restricting the benzene leaving the vapor stream to less than 20 \\% of the benzene available in the reactor outlet. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.673507300Z", + "start_time": "2026-02-25T17:35:07.666381200Z" + } + }, + "source": [ + "m.fs.overhead_loss = Constraint(\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + ")" + ], + "outputs": [], + "execution_count": 64 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "solution" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.707964Z", + "start_time": "2026-02-25T17:35:07.699126100Z" + } + }, + "source": [ + "# Todo: Add minimum product flow constraint\n", + "m.fs.product_flow = Constraint(\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " >= 0.15\n", + ")" + ], + "outputs": [], + "execution_count": 66 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us add the final constraint on product purity or the mole fraction of benzene in the product stream such that it is at least greater than 80%. " + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.718982700Z", + "start_time": "2026-02-25T17:35:07.711201900Z" + } + }, + "source": [ + "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" + ], + "outputs": [], + "execution_count": 67 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "We have now defined the optimization problem and we are now ready to solve this problem. \n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.837157700Z", + "start_time": "2026-02-25T17:35:07.721454600Z" + } + }, + "source": "results = solver.solve(m, tee=False)", + "outputs": [], + "execution_count": 68 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.846796Z", + "start_time": "2026-02-25T17:35:07.839188400Z" + } + }, + "source": [ + "# Check for solver solve status\n", + "from pyomo.environ import TerminationCondition\n", + "\n", + "assert results.solver.termination_condition == TerminationCondition.optimal" + ], + "outputs": [], + "execution_count": 69 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 8.1 Optimization Results\n", + "\n", + "Display the results and product specifications" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.883912Z", + "start_time": "2026-02-25T17:35:07.847804400Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 312674.2367538264\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 8370.2 : watt : False : (None, None)\n", + " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 0.28812 - - \n", + " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", + " Temperature kelvin 301.88 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", + " temperature kelvin - 362.93 362.93 \n", + " pressure pascal - 1.0500e+05 1.0500e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.818829588839798\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -42942. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", + " Total Molar Flowrate Vap mole / second 1.9480 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", + " Temperature kelvin 600.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", + " temperature kelvin - 301.88 301.88 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 70 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.893574600Z", + "start_time": "2026-02-25T17:35:07.884912500Z" + } + }, + "source": [ + "assert value(m.fs.operating_cost) == pytest.approx(312674.236, abs=1e-3)\n", + "assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3)" + ], + "outputs": [], + "execution_count": 71 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display optimal values for the decision variables" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.924695400Z", + "start_time": "2026-02-25T17:35:07.893574600Z" + } + }, + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 heat duty = -13766.243 W\n", + "\n", + "F101 outlet temperature = 301.881 K\n", + "\n", + "F102 outlet temperature = 362.935 K\n", + "F102 outlet pressure = 105000.000 Pa\n", + "\n" + ] + } + ], + "execution_count": 72 + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "testing" + ], + "ExecuteTime": { + "end_time": "2026-02-25T17:35:07.935546Z", + "start_time": "2026-02-25T17:35:07.925710Z" + } + }, + "source": [ + "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3)\n", + "assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, abs=1e-3)\n", + "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, abs=1e-3)\n", + "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, abs=1e-3)\n", + "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2)" + ], + "outputs": [], + "execution_count": 73 } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Values:\n", - "\n", - "H101 outlet temperature = 500.000 K\n", - "\n", - "R101 heat duty = -13766.243 W\n", - "\n", - "F101 outlet temperature = 301.881 K\n", - "\n", - "F102 outlet temperature = 362.935 K\n", - "F102 outlet pressure = 105000.000 Pa\n", - "\n" - ] + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" } - ], - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-25T17:35:55.622383200Z", - "start_time": "2026-02-25T17:35:55.610031600Z" - }, - "execution": { - "iopub.execute_input": "2026-02-25T17:37:03.676747Z", - "iopub.status.busy": "2026-02-25T17:37:03.676747Z", - "iopub.status.idle": "2026-02-25T17:37:03.680784Z", - "shell.execute_reply": "2026-02-25T17:37:03.680784Z" - }, - "tags": [ - "testing" - ] - }, - "outputs": [], - "source": [ - "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3)\n", - "assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, abs=1e-3)\n", - "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2)" - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.11" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file From a6d68c5b33faa1f69b5830aca5b698db37c13d79 Mon Sep 17 00:00:00 2001 From: Doug A Date: Wed, 22 Jul 2026 13:03:11 -0400 Subject: [PATCH 2/2] make sure changes to hda flowsheet stick --- .../docs/tut/core/hda_flowsheet.ipynb | 902 +++++++------ .../notebooks/docs/tut/core/hda_flowsheet.py | 1125 ----------------- .../docs/tut/core/hda_flowsheet_doc.ipynb | 614 +++++---- .../tut/core/hda_flowsheet_exercise.ipynb | 626 +++++---- .../tut/core/hda_flowsheet_solution.ipynb | 754 ++++++----- .../docs/tut/core/hda_flowsheet_test.ipynb | 762 ++++++----- .../docs/tut/core/hda_flowsheet_usr.ipynb | 754 ++++++----- 7 files changed, 2140 insertions(+), 3397 deletions(-) delete mode 100644 idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb index a210686d..5ef8ec73 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb @@ -2,16 +2,18 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "metadata": { - "tags": [ - "header", - "hide-cell" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:01.286374300Z", "start_time": "2026-02-25T17:35:01.274737700Z" - } + }, + "tags": [ + "header", + "hide-cell" + ] }, + "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -25,9 +27,7 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -119,12 +119,14 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:01.830457200Z", "start_time": "2026-02-25T17:35:01.290402400Z" } }, + "outputs": [], "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -136,9 +138,7 @@ " value,\n", ")\n", "from pyomo.network import Arc" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -157,24 +157,28 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.665835Z", "start_time": "2026-02-25T17:35:01.832975100Z" } }, - "source": "from idaes.core import FlowsheetBlock", "outputs": [], - "execution_count": 3 + "source": [ + "from idaes.core import FlowsheetBlock" + ] }, { "cell_type": "code", + "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.734656600Z", "start_time": "2026-02-25T17:35:03.667871Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -185,9 +189,7 @@ " Feed,\n", " Product,\n", ")" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -201,38 +203,38 @@ }, { "cell_type": "code", + "execution_count": 5, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.744136400Z", "start_time": "2026-02-25T17:35:03.736701700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ], - "outputs": [], - "execution_count": 5 + ] }, { "cell_type": "code", + "execution_count": 6, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.752580Z", "start_time": "2026-02-25T17:35:03.745137800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -243,21 +245,21 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.761528300Z", "start_time": "2026-02-25T17:35:03.753588300Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", "from idaes.core.solvers import get_solver" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -278,13 +280,15 @@ ] }, { + "cell_type": "code", + "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.838559500Z", "start_time": "2026-02-25T17:35:03.761528300Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "from idaes.models.properties.modular_properties.base.generic_property import (\n", " GenericParameterBlock,\n", @@ -294,9 +298,7 @@ ")\n", "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -309,18 +311,18 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.849781Z", "start_time": "2026-02-25T17:35:03.841636100Z" } }, + "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "markdown", @@ -331,20 +333,20 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.879447Z", "start_time": "2026-02-25T17:35:03.851130600Z" } }, + "outputs": [], "source": [ "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", "m.fs.reaction_params = GenericReactionParameterBlock(\n", " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -357,12 +359,14 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.925685100Z", "start_time": "2026-02-25T17:35:03.881771100Z" } }, + "outputs": [], "source": [ "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", @@ -377,9 +381,7 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ], - "outputs": [], - "execution_count": 11 + ] }, { "cell_type": "markdown", @@ -404,32 +406,34 @@ }, { "cell_type": "code", + "execution_count": 12, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.935108600Z", "start_time": "2026-02-25T17:35:03.927715700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ], - "outputs": [], - "execution_count": 12 + ] }, { "cell_type": "code", + "execution_count": 13, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.956022500Z", "start_time": "2026-02-25T17:35:03.935614400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -439,9 +443,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ], - "outputs": [], - "execution_count": 13 + ] }, { "cell_type": "markdown", @@ -457,21 +459,21 @@ }, { "cell_type": "code", + "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.979104400Z", "start_time": "2026-02-25T17:35:03.958076200Z" } }, + "outputs": [], "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "markdown", @@ -482,12 +484,14 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.031371300Z", "start_time": "2026-02-25T17:35:03.981638100Z" } }, + "outputs": [], "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -507,9 +511,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 15 + ] }, { "cell_type": "markdown", @@ -520,19 +522,19 @@ }, { "cell_type": "code", + "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.049278900Z", "start_time": "2026-02-25T17:35:04.033910400Z" } }, + "outputs": [], "source": [ "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ], - "outputs": [], - "execution_count": 16 + ] }, { "cell_type": "markdown", @@ -552,19 +554,19 @@ }, { "cell_type": "code", + "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.059097Z", "start_time": "2026-02-25T17:35:04.051649500Z" } }, + "outputs": [], "source": [ "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ], - "outputs": [], - "execution_count": 17 + ] }, { "cell_type": "markdown", @@ -582,38 +584,38 @@ }, { "cell_type": "code", + "execution_count": 18, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.067198800Z", "start_time": "2026-02-25T17:35:04.059097Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ], - "outputs": [], - "execution_count": 18 + ] }, { "cell_type": "code", + "execution_count": 19, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.074873700Z", "start_time": "2026-02-25T17:35:04.067198800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ], - "outputs": [], - "execution_count": 19 + ] }, { "cell_type": "markdown", @@ -624,21 +626,21 @@ }, { "cell_type": "code", + "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.082717500Z", "start_time": "2026-02-25T17:35:04.075379Z" } }, + "outputs": [], "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ], - "outputs": [], - "execution_count": 20 + ] }, { "cell_type": "markdown", @@ -649,19 +651,19 @@ }, { "cell_type": "code", + "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.091461Z", "start_time": "2026-02-25T17:35:04.083716700Z" } }, + "outputs": [], "source": [ "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ], - "outputs": [], - "execution_count": 21 + ] }, { "cell_type": "markdown", @@ -672,17 +674,17 @@ }, { "cell_type": "code", + "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.116142500Z", "start_time": "2026-02-25T17:35:04.092591700Z" } }, + "outputs": [], "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ], - "outputs": [], - "execution_count": 22 + ] }, { "cell_type": "markdown", @@ -704,12 +706,14 @@ }, { "cell_type": "code", + "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.126991900Z", "start_time": "2026-02-25T17:35:04.118294Z" } }, + "outputs": [], "source": [ "m.fs.purity = Expression(\n", " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -722,9 +726,7 @@ " ]\n", " )\n", ")" - ], - "outputs": [], - "execution_count": 23 + ] }, { "cell_type": "markdown", @@ -735,19 +737,19 @@ }, { "cell_type": "code", + "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.134981600Z", "start_time": "2026-02-25T17:35:04.126991900Z" } }, + "outputs": [], "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ], - "outputs": [], - "execution_count": 24 + ] }, { "cell_type": "markdown", @@ -764,19 +766,19 @@ }, { "cell_type": "code", + "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.142918500Z", "start_time": "2026-02-25T17:35:04.134981600Z" } }, + "outputs": [], "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ], - "outputs": [], - "execution_count": 25 + ] }, { "cell_type": "markdown", @@ -787,19 +789,19 @@ }, { "cell_type": "code", + "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.151633300Z", "start_time": "2026-02-25T17:35:04.143918400Z" } }, + "outputs": [], "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ], - "outputs": [], - "execution_count": 26 + ] }, { "cell_type": "markdown", @@ -813,15 +815,13 @@ }, { "cell_type": "code", + "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.183600800Z", "start_time": "2026-02-25T17:35:04.152655800Z" } }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -831,25 +831,27 @@ ] } ], - "execution_count": 27 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "code", + "execution_count": 28, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.216388800Z", "start_time": "2026-02-25T17:35:04.187853900Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 29" - ], - "outputs": [], - "execution_count": 28 + ] }, { "cell_type": "markdown", @@ -863,19 +865,19 @@ }, { "cell_type": "code", + "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.227743300Z", "start_time": "2026-02-25T17:35:04.218810900Z" } }, + "outputs": [], "source": [ "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", "\n", "tear_guesses = fix_inlet_states(m)" - ], - "outputs": [], - "execution_count": 29 + ] }, { "cell_type": "markdown", @@ -888,17 +890,17 @@ }, { "cell_type": "code", + "execution_count": 30, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.235882200Z", "start_time": "2026-02-25T17:35:04.227743300Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ], - "outputs": [], - "execution_count": 30 + ] }, { "cell_type": "markdown", @@ -909,12 +911,14 @@ }, { "cell_type": "code", + "execution_count": 31, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.257770300Z", "start_time": "2026-02-25T17:35:04.236888500Z" } }, + "outputs": [], "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", @@ -931,9 +935,7 @@ "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ], - "outputs": [], - "execution_count": 31 + ] }, { "cell_type": "markdown", @@ -944,18 +946,18 @@ }, { "cell_type": "code", + "execution_count": 32, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.268846Z", "start_time": "2026-02-25T17:35:04.260299600Z" } }, + "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ], - "outputs": [], - "execution_count": 32 + ] }, { "cell_type": "markdown", @@ -979,38 +981,38 @@ }, { "cell_type": "code", + "execution_count": 33, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.278171500Z", "start_time": "2026-02-25T17:35:04.269857200Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ], - "outputs": [], - "execution_count": 33 + ] }, { "cell_type": "code", + "execution_count": 34, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.288481300Z", "start_time": "2026-02-25T17:35:04.279196300Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ], - "outputs": [], - "execution_count": 34 + ] }, { "cell_type": "markdown", @@ -1021,18 +1023,18 @@ }, { "cell_type": "code", + "execution_count": 35, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.302496300Z", "start_time": "2026-02-25T17:35:04.289482700Z" } }, + "outputs": [], "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ], - "outputs": [], - "execution_count": 35 + ] }, { "cell_type": "markdown", @@ -1052,35 +1054,33 @@ }, { "cell_type": "code", + "execution_count": 36, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.312730200Z", "start_time": "2026-02-25T17:35:04.305395100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ], - "outputs": [], - "execution_count": 36 + ] }, { "cell_type": "code", + "execution_count": 37, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.340811100Z", "start_time": "2026-02-25T17:35:04.313761800Z" - } + }, + "tags": [ + "solution" + ] }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -1090,25 +1090,27 @@ ] } ], - "execution_count": 37 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "code", + "execution_count": 38, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.374728400Z", "start_time": "2026-02-25T17:35:04.345879200Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 0" - ], - "outputs": [], - "execution_count": 38 + ] }, { "cell_type": "markdown", @@ -1132,25 +1134,28 @@ ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "First, we will highlight some helpful functions that are used in the initialization process." + "metadata": {}, + "source": [ + "First, we will highlight some helpful functions that are used in the initialization process." + ] }, { + "cell_type": "code", + "execution_count": 39, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.386344500Z", "start_time": "2026-02-25T17:35:04.376804600Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def initialize_unit(unit):\n", " from idaes.core.util.exceptions import InitializationError\n", " import idaes.logger as idaeslog\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", @@ -1162,9 +1167,7 @@ " except InitializationError:\n", " solver = get_solver(solver_options=optarg)\n", " solver.solve(unit)" - ], - "outputs": [], - "execution_count": 39 + ] }, { "cell_type": "markdown", @@ -1181,13 +1184,15 @@ ] }, { + "cell_type": "code", + "execution_count": 40, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.394802500Z", "start_time": "2026-02-25T17:35:04.386344500Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def automatic_propagation(m, tear_guesses):\n", "\n", @@ -1212,9 +1217,7 @@ " print(o[0].name)\n", "\n", " seq.run(m, initialize_unit)" - ], - "outputs": [], - "execution_count": 40 + ] }, { "cell_type": "markdown", @@ -1226,16 +1229,18 @@ ] }, { + "cell_type": "code", + "execution_count": 41, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.404491500Z", "start_time": "2026-02-25T17:35:04.396317500Z" } }, - "cell_type": "code", - "source": "# automatic_propagation(m, tear_guesses)", "outputs": [], - "execution_count": 41 + "source": [ + "# automatic_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1249,12 +1254,14 @@ }, { "cell_type": "code", + "execution_count": 42, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.417815100Z", "start_time": "2026-02-25T17:35:04.404995800Z" } }, + "outputs": [], "source": [ "def manual_propagation(m, tear_guesses):\n", " from idaes.core.util.initialization import propagate_state\n", @@ -1270,7 +1277,6 @@ " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " # \"tol\": 1e-10,\n", @@ -1311,7 +1317,6 @@ " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " \"tol\": 1e-8,\n", @@ -1327,9 +1332,7 @@ " print(\n", " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", " )" - ], - "outputs": [], - "execution_count": 42 + ] }, { "cell_type": "markdown", @@ -1344,13 +1347,13 @@ }, { "cell_type": "code", + "execution_count": 43, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.145125500Z", "start_time": "2026-02-25T17:35:04.419335500Z" } }, - "source": "manual_propagation(m, tear_guesses)", "outputs": [ { "name": "stdout", @@ -1363,7 +1366,9 @@ ] } ], - "execution_count": 43 + "source": [ + "manual_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1383,22 +1388,21 @@ }, { "cell_type": "code", + "execution_count": 44, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.161129400Z", "start_time": "2026-02-25T17:35:07.146644300Z" } }, + "outputs": [], "source": [ "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", "}" - ], - "outputs": [], - "execution_count": 44 + ] }, { "cell_type": "markdown", @@ -1421,63 +1425,63 @@ }, { "cell_type": "code", + "execution_count": 45, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.170980400Z", "start_time": "2026-02-25T17:35:07.163178100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "\n", "# Solve the model" - ], - "outputs": [], - "execution_count": 45 + ] }, { "cell_type": "code", + "execution_count": 46, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.272798500Z", "start_time": "2026-02-25T17:35:07.170980400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=False)" - ], - "outputs": [], - "execution_count": 46 + ] }, { "cell_type": "code", + "execution_count": 47, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.281939700Z", "start_time": "2026-02-25T17:35:07.274820400Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 47 + ] }, { "cell_type": "markdown", @@ -1497,20 +1501,20 @@ }, { "cell_type": "code", + "execution_count": 48, "metadata": { - "tags": [ - "noauto" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.302463Z", "start_time": "2026-02-25T17:35:07.282944100Z" - } + }, + "tags": [ + "noauto" + ] }, + "outputs": [], "source": [ "# m.fs.visualize(\"HDA-Flowsheet\")" - ], - "outputs": [], - "execution_count": 48 + ] }, { "cell_type": "markdown", @@ -1521,15 +1525,13 @@ }, { "cell_type": "code", + "execution_count": 49, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.337983600Z", "start_time": "2026-02-25T17:35:07.303479400Z" } }, - "source": [ - "m.fs.report()" - ], "outputs": [ { "name": "stdout", @@ -1541,21 +1543,23 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 1.6736e-09 1.8681e-09 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7852e-07\n", " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.8212e-08 1.8212e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.8268e-08 4.8268e-08 0.72074\n", " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", "====================================================================================\n" ] } ], - "execution_count": 49 + "source": [ + "m.fs.report()" + ] }, { "cell_type": "markdown", @@ -1566,44 +1570,44 @@ }, { "cell_type": "code", + "execution_count": 50, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.355013500Z", "start_time": "2026-02-25T17:35:07.346055600Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 419008.28211932775\n" + "operating cost = $ 419008.28599155403\n" ] } ], - "execution_count": 50 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ] }, { "cell_type": "code", + "execution_count": 51, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.449306200Z", "start_time": "2026-02-25T17:35:07.358159700Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "import pytest\n", "\n", - "assert value(m.fs.operating_cost) == pytest.approx(419008.28189, abs=1e-3)" - ], - "outputs": [], - "execution_count": 51 + "assert value(m.fs.operating_cost) == pytest.approx(419008.28189, rel=1e-4)" + ] }, { "cell_type": "markdown", @@ -1614,18 +1618,13 @@ }, { "cell_type": "code", + "execution_count": 52, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.469810Z", "start_time": "2026-02-25T17:35:07.452663800Z" } }, - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ], "outputs": [ { "name": "stdout", @@ -1646,52 +1645,47 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", + " flow_mol_phase Liq mole / second 0.26712 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.76595 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.23405 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.084499 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0088437 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18592 1.8212e-08 1.8212e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.72074 4.8268e-08 4.8268e-08 \n", + " temperature kelvin 325.00 375.00 375.00 \n", + " pressure pascal 3.5000e+05 1.5000e+05 1.5000e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.8242963521555953\n" + "benzene purity = 0.8242963399526197\n" ] } ], - "execution_count": 52 + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ] }, { "cell_type": "code", + "execution_count": 53, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.486974600Z", "start_time": "2026-02-25T17:35:07.477988200Z" - } + }, + "tags": [ + "testing" + ] }, - "source": [ - "assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3)\n", - "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3)" - ], "outputs": [], - "execution_count": 53 + "source": [ + "assert value(m.fs.purity) == pytest.approx(0.82429, rel=1e-4)\n", + "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, rel=1e-4)\n", + "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, rel=1e-4)" + ] }, { "cell_type": "markdown", @@ -1702,28 +1696,20 @@ }, { "cell_type": "code", + "execution_count": 54, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.503351300Z", "start_time": "2026-02-25T17:35:07.487979400Z" } }, - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Liq mole / second 1.8681e-09 1.0000e-08 \n", "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", @@ -1736,7 +1722,15 @@ ] } ], - "execution_count": 54 + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ] }, { "cell_type": "markdown", @@ -1769,17 +1763,17 @@ }, { "cell_type": "code", + "execution_count": 55, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.523495700Z", "start_time": "2026-02-25T17:35:07.513232100Z" } }, + "outputs": [], "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ], - "outputs": [], - "execution_count": 55 + ] }, { "cell_type": "markdown", @@ -1792,21 +1786,21 @@ }, { "cell_type": "code", + "execution_count": 56, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.538051100Z", "start_time": "2026-02-25T17:35:07.528058900Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.R101.outlet.temperature.fix(600)\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ], - "outputs": [], - "execution_count": 56 + ] }, { "cell_type": "markdown", @@ -1827,53 +1821,55 @@ }, { "cell_type": "code", + "execution_count": 57, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.568196100Z", "start_time": "2026-02-25T17:35:07.545899Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ], - "outputs": [], - "execution_count": 57 + ] }, { "cell_type": "code", + "execution_count": 58, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.578318700Z", "start_time": "2026-02-25T17:35:07.571295800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ], - "outputs": [], - "execution_count": 58 + ] }, { "cell_type": "code", + "execution_count": 59, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.616492Z", "start_time": "2026-02-25T17:35:07.581710400Z" - } + }, + "tags": [ + "testing" + ] }, - "source": "assert degrees_of_freedom(m) == 4", "outputs": [], - "execution_count": 59 + "source": [ + "assert degrees_of_freedom(m) == 4" + ] }, { "cell_type": "markdown", @@ -1891,18 +1887,18 @@ }, { "cell_type": "code", + "execution_count": 60, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.627054600Z", "start_time": "2026-02-25T17:35:07.619525700Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ], - "outputs": [], - "execution_count": 60 + ] }, { "cell_type": "markdown", @@ -1922,37 +1918,39 @@ }, { "cell_type": "code", + "execution_count": 61, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.638684200Z", "start_time": "2026-02-25T17:35:07.630104900Z" - } + }, + "tags": [ + "exercise" + ] }, - "source": "# Todo: Set the bounds for flash 101 outlet temperature", "outputs": [], - "execution_count": 61 + "source": [ + "# Todo: Set the bounds for flash 101 outlet temperature" + ] }, { "cell_type": "code", + "execution_count": 62, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.652892600Z", "start_time": "2026-02-25T17:35:07.643756900Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" - ], - "outputs": [], - "execution_count": 62 + ] }, { "cell_type": "markdown", @@ -1963,20 +1961,20 @@ }, { "cell_type": "code", + "execution_count": 63, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.662831700Z", "start_time": "2026-02-25T17:35:07.654919400Z" } }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ], - "outputs": [], - "execution_count": 63 + ] }, { "cell_type": "markdown", @@ -1987,12 +1985,14 @@ }, { "cell_type": "code", + "execution_count": 64, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.673507300Z", "start_time": "2026-02-25T17:35:07.666381200Z" } }, + "outputs": [], "source": [ "m.fs.overhead_loss = Constraint(\n", " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -2001,9 +2001,7 @@ " <= 0.20\n", " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ], - "outputs": [], - "execution_count": 64 + ] }, { "cell_type": "markdown", @@ -2023,32 +2021,34 @@ }, { "cell_type": "code", + "execution_count": 65, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.688400300Z", "start_time": "2026-02-25T17:35:07.677541500Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ], - "outputs": [], - "execution_count": 65 + ] }, { "cell_type": "code", + "execution_count": 66, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.707964Z", "start_time": "2026-02-25T17:35:07.699126100Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", @@ -2057,9 +2057,7 @@ " ]\n", " >= 0.15\n", ")" - ], - "outputs": [], - "execution_count": 66 + ] }, { "cell_type": "markdown", @@ -2070,17 +2068,17 @@ }, { "cell_type": "code", + "execution_count": 67, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.718982700Z", "start_time": "2026-02-25T17:35:07.711201900Z" } }, + "outputs": [], "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ], - "outputs": [], - "execution_count": 67 + ] }, { "cell_type": "markdown", @@ -2094,35 +2092,37 @@ }, { "cell_type": "code", + "execution_count": 68, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.837157700Z", "start_time": "2026-02-25T17:35:07.721454600Z" } }, - "source": "results = solver.solve(m, tee=False)", "outputs": [], - "execution_count": 68 + "source": [ + "results = solver.solve(m, tee=False)" + ] }, { "cell_type": "code", + "execution_count": 69, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.846796Z", "start_time": "2026-02-25T17:35:07.839188400Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check for solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 69 + ] }, { "cell_type": "markdown", @@ -2135,33 +2135,19 @@ }, { "cell_type": "code", + "execution_count": 70, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.883912Z", "start_time": "2026-02-25T17:35:07.847804400Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 312674.2367538264\n", + "operating cost = $ 312674.23682387645\n", "\n", "Product flow rate and purity in F102\n", "\n", @@ -2179,29 +2165,19 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", + " flow_mol_phase Liq mole / second 0.28812 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.75463 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.24537 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.032748 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0032478 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.21614 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.74786 4.0825e-08 4.0825e-08 \n", + " temperature kelvin 301.88 362.93 362.93 \n", + " pressure pascal 3.5000e+05 1.0500e+05 1.0500e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.818829588839798\n", + "benzene purity = 0.8188295887582271\n", "\n", "Overhead loss in F101\n", "\n", @@ -2219,49 +2195,53 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", + " flow_mol_phase Liq mole / second 2.6866e-12 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second 1.9480 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.57381 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.42619 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.13952 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.039059 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18417 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.63725 0.74786 0.74786 \n", + " temperature kelvin 600.00 301.88 301.88 \n", + " pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 \n", "====================================================================================\n" ] } ], - "execution_count": 70 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ] }, { "cell_type": "code", + "execution_count": 71, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.893574600Z", "start_time": "2026-02-25T17:35:07.884912500Z" - } + }, + "tags": [ + "testing" + ] }, - "source": [ - "assert value(m.fs.operating_cost) == pytest.approx(312674.236, abs=1e-3)\n", - "assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3)" - ], "outputs": [], - "execution_count": 71 + "source": [ + "assert value(m.fs.operating_cost) == pytest.approx(312674.236, rel=1e-4)\n", + "assert value(m.fs.purity) == pytest.approx(0.818827, rel=1e-4)" + ] }, { "cell_type": "markdown", @@ -2272,27 +2252,13 @@ }, { "cell_type": "code", + "execution_count": 72, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.924695400Z", "start_time": "2026-02-25T17:35:07.893574600Z" } }, - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ], "outputs": [ { "name": "stdout", @@ -2312,28 +2278,42 @@ ] } ], - "execution_count": 72 + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ] }, { "cell_type": "code", + "execution_count": 73, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.935546Z", "start_time": "2026-02-25T17:35:07.925710Z" - } + }, + "tags": [ + "testing" + ] }, - "source": [ - "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3)\n", - "assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, abs=1e-3)\n", - "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2)" - ], "outputs": [], - "execution_count": 73 + "source": [ + "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, rel=1e-4)\n", + "assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, rel=1e-4)\n", + "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, rel=1e-4)\n", + "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, rel=1e-4)\n", + "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, rel=1e-4)" + ] } ], "metadata": { @@ -2353,7 +2333,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.12.0" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py deleted file mode 100644 index 3fcf9278..00000000 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py +++ /dev/null @@ -1,1125 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - -# In[1]: - - -############################################################################### -# 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-2026 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. -############################################################################### - - -# -# # HDA Flowsheet Simulation and Optimization -# -# Author: Jaffer Ghouse
-# Maintainer: Tanner Polley
-# Updated: 2026-1-12 -# -# ## Learning outcomes -# -# -# - Construct a steady-state flowsheet using the IDAES unit model library -# - Connecting unit models in a flowsheet using Arcs -# - Using the SequentialDecomposition tool to initialize a flowsheet with recycle -# - Formulate and solve an optimization problem -# - Defining an objective function -# - Setting variable bounds -# - Adding additional constraints -# -# -# The general workflow of setting up an IDAES flowsheet is the following: -# -#      1 Importing Modules
-#      2 Building a Model
-#      3 Scaling the Model
-#      4 Specifying the Model
-#      5 Initializing the Model
-#      6 Solving the Model
-#      7 Analyzing and Visualizing the Results
-#      8 Optimizing the Model
-# -# We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises. -# -# -# ## Problem Statement -# -# Hydrodealkylation is a chemical reaction that often involves reacting -# an aromatic hydrocarbon in the presence of hydrogen gas to form a -# simpler aromatic hydrocarbon devoid of functional groups. In this -# example, toluene will be reacted with hydrogen gas at high temperatures -# to form benzene via the following reaction: -# -# **C6H5CH3 + H2 → C6H6 + CH4** -# -# -# This reaction is often accompanied by an equilibrium side reaction -# which forms diphenyl, which we will neglect for this example. -# -# This example is based on the 1967 AIChE Student Contest problem as -# present by Douglas, J.M., Chemical Design of Chemical Processes, 1988, -# McGraw-Hill. -# -# The flowsheet that we will be using for this module is shown below with the stream conditions. We will be processing toluene and hydrogen to produce at least 370 TPY of benzene. As shown in the flowsheet, there are two flash tanks, F101 to separate out the non-condensibles and F102 to further separate the benzene-toluene mixture to improve the benzene purity. Note that typically a distillation column is required to obtain high purity benzene but that is beyond the scope of this workshop. The non-condensibles separated out in F101 will be partially recycled back to M101 and the rest will be either purged or combusted for power generation.We will assume ideal gas for this flowsheet. The properties required for this module are available in the same directory: -# -# - hda_ideal_VLE.py -# - hda_reaction.py -# -# The state variables chosen for the property package are **flows of component by phase, temperature and pressure**. The components considered are: **toluene, hydrogen, benzene and methane**. Therefore, every stream has 8 flow variables, 1 temperature and 1 pressure variable. -# -# ![](HDA_flowsheet.png) -# -# - -# ## 1 Importing Modules -# ### 1.1 Importing required Pyomo and IDAES components -# -# -# To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo: -# - Constraint (to write constraints) -# - Var (to declare variables) -# - ConcreteModel (to create the concrete model object) -# - Expression (to evaluate values as a function of variables defined in the model) -# - Objective (to define an objective function for optimization) -# - SolverFactory (to solve the problem) -# - TransformationFactory (to apply certain transformations) -# - Arc (to connect two unit models) -# - SequentialDecomposition (to initialize the flowsheet in a sequential mode) -# -# For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/ -# - -# In[2]: - - -from pyomo.environ import ( - Constraint, - Var, - ConcreteModel, - Expression, - Objective, - TransformationFactory, - value, -) -from pyomo.network import Arc - - -# From IDAES, we will be needing the FlowsheetBlock and the following unit models: -# - Feed -# - Mixer -# - Heater -# - StoichiometricReactor -# - **Flash** -# - Separator (splitter) -# - PressureChanger -# - Product - -# In[3]: - - -from idaes.core import FlowsheetBlock - - -# In[4]: - - -from idaes.models.unit_models import ( - PressureChanger, - Mixer, - Separator as Splitter, - Heater, - StoichiometricReactor, - Feed, - Product, -) - - -#
-# Inline Exercise: -# Now, import the remaining unit models highlighted in blue above and run the cell using `Shift+Enter` after typing in the code. -#
-# - -# In[5]: - - -# Todo: import flash model from idaes.models.unit_models - - -# In[6]: - - -# Todo: import flash model from idaes.models.unit_models -from idaes.models.unit_models import Flash - - -# We will also be needing some utility tools to put together the flowsheet and calculate the degrees of freedom. - -# In[7]: - - -from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption -from idaes.core.util.model_statistics import degrees_of_freedom - -# Import idaes logger to set output levels -from idaes.core.solvers import get_solver - - -# ### 1.2 Importing required thermo and reaction package -# -# The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. -# -# The reaction package here is very simple as we will be using only a StochiometricReactor and the reaction package consists of the stochiometric coefficients for the reaction and the parameter for the heat of reaction. -# -# Let us import the following modules and they are in the same directory as this jupyter notebook: -#
    -#
  • hda_ideal_VLE as thermo_props
  • -#
  • hda_reaction as reaction_props
  • -#
-# - -# In[8]: - - -from idaes.models.properties.modular_properties.base.generic_property import ( - GenericParameterBlock, -) -from idaes.models.properties.modular_properties.base.generic_reaction import ( - GenericReactionParameterBlock, -) -from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config -from idaes_examples.mod.hda.hda_reaction_modular import reaction_config - - -# ## 2 Constructing the Flowsheet -# -# We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block. - -# In[9]: - - -m = ConcreteModel() -m.fs = FlowsheetBlock(dynamic=False) - - -# We now need to add the property packages to the flowsheet. Unlike Module 1, where we only had a thermo property package, for this flowsheet we will also need to add a reaction property package. - -# In[10]: - - -m.fs.thermo_params = GenericParameterBlock(**thermo_config) -m.fs.reaction_params = GenericReactionParameterBlock( - property_package=m.fs.thermo_params, **reaction_config -) - - -# ### 2.1 Adding Unit Models -# -# Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`. - -# In[11]: - - -m.fs.I101 = Feed(property_package=m.fs.thermo_params) -m.fs.I102 = Feed(property_package=m.fs.thermo_params) - -m.fs.M101 = Mixer( - property_package=m.fs.thermo_params, - num_inlets=3, -) - -m.fs.H101 = Heater( - property_package=m.fs.thermo_params, - has_pressure_change=False, - has_phase_equilibrium=True, -) - - -#
-# Inline Exercise: -# Let us now add the StoichiometricReactor(assign the name R101) and pass the following arguments: -#
    -#
  • "property_package": m.fs.thermo_params
  • -#
  • "reaction_package": m.fs.reaction_params
  • -#
  • "has_heat_of_reaction": True
  • -#
  • "has_heat_transfer": True
  • -#
  • "has_pressure_change": False
  • -#
-#
- -# In[12]: - - -# Todo: Add reactor with the specifications above - - -# In[13]: - - -# Todo: Add reactor with the specifications above -m.fs.R101 = StoichiometricReactor( - property_package=m.fs.thermo_params, - reaction_package=m.fs.reaction_params, - has_heat_of_reaction=True, - has_heat_transfer=True, - has_pressure_change=False, -) - - -# Let us now add the Flash(assign the name F101) and pass the following arguments: -#
    -#
  • "property_package": m.fs.thermo_params
  • -#
  • "has_heat_transfer": True
  • -#
  • "has_pressure_change": False
  • -#
- -# In[14]: - - -m.fs.F101 = Flash( - property_package=m.fs.thermo_params, - has_heat_transfer=True, - has_pressure_change=True, -) - - -# Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102). - -# In[15]: - - -m.fs.S101 = Splitter( - property_package=m.fs.thermo_params, - ideal_separation=False, - outlet_list=["purge", "recycle"], -) - - -m.fs.C101 = PressureChanger( - property_package=m.fs.thermo_params, - compressor=True, - thermodynamic_assumption=ThermodynamicAssumption.isothermal, -) - -m.fs.F102 = Flash( - property_package=m.fs.thermo_params, - has_heat_transfer=True, - has_pressure_change=True, -) - - -# Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency - -# In[16]: - - -m.fs.P101 = Product(property_package=m.fs.thermo_params) -m.fs.P102 = Product(property_package=m.fs.thermo_params) -m.fs.P103 = Product(property_package=m.fs.thermo_params) - - -# ### 2.2 Connecting Unit Models using Arcs -# -# We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101). - -# ![](HDA_flowsheet.png) - -# In[17]: - - -m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1) -m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2) -m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet) - - -#
-# Inline Exercise: -# Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. -#
- -# In[18]: - - -# Todo: Connect the H101 outlet to R101 inlet - - -# In[19]: - - -# Todo: Connect the H101 outlet to R101 inlet -m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet) - - -# We will now be connecting the rest of the flowsheet as shown below. Notice how the outlet names are different for the flash tanks F101 and F102 as they have a vapor and a liquid outlet. - -# In[20]: - - -m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet) -m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet) -m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet) -m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet) -m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3) - - -# Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103) - -# In[21]: - - -m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet) -m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet) -m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet) - - -# We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows: - -# In[22]: - - -TransformationFactory("network.expand_arcs").apply_to(m) - - -# ### 2.3 Adding expressions to compute purity and operating costs -# -# In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html. -# -# For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. - -# Let us first add an Expression to compute the mole fraction of benzene in the `vap_outlet` of F102 which is our product stream. Please note that the var flow_mol_phase_comp has the index - [time, phase, component]. As this is a steady-state flowsheet, the time index by default is 0. The valid phases are ["Liq", "Vap"]. Similarly the valid component list is ["benzene", "toluene", "hydrogen", "methane"]. - -# In[23]: - - -m.fs.purity = Expression( - expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" - ] - / ( - m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp["Vap", "benzene"] - + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "toluene" - ] - ) -) - - -# Now, let us add an expression to compute the cooling cost assuming a cost of 0.212E-4 $/kW. Note that cooling utility is required for the reactor (R101) and the first flash (F101). - -# In[24]: - - -m.fs.cooling_cost = Expression( - expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0]) -) - - -# -# Now, let us add an expression to compute the heating cost assuming the utility cost as follows: -#
    -#
  • 2.2E-4 dollars/kW for H101
  • -#
  • 1.9E-4 dollars/kW for F102
  • -#
-# Note that the heat duty is in units of watt (J/s). - -# In[25]: - - -m.fs.heating_cost = Expression( - expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0] -) - - -# Let us now add an expression to compute the total operating cost per year which is basically the sum of the cooling and heating cost we defined above. - -# In[26]: - - -m.fs.operating_cost = Expression( - expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost)) -) - - -# ## 4 Specifying the Model -# ### 4.1 Fixing feed conditions -# -# Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. - -# In[27]: - - -print(degrees_of_freedom(m)) - - -# In[28]: - - -# Check the degrees of freedom -assert degrees_of_freedom(m) == 29 - - -# We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note -# that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to -# help with convergence and initializing. We will be importing a function that will specify the inlet conditions for -# this example. - -# In[29]: - - -from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states - -tear_guesses = fix_inlet_states(m) - - -# ### 4.2 Fixing unit model specifications -# -# Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. - -# In[30]: - - -m.fs.H101.outlet.temperature.fix(600) - - -# For the StoichiometricReactor, we have to define the conversion in terms of toluene. This requires us to create a new variable for specifying the conversion and adding a Constraint that defines the conversion with respect to toluene. The second degree of freedom for the reactor is to define the heat duty. In this case, let us assume the reactor to be adiabatic i.e. Q = 0. - -# In[31]: - - -m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1)) - -m.fs.R101.conv_constraint = Constraint( - expr=m.fs.R101.conversion - * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp["Vap", "toluene"]) - == ( - m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp["Vap", "toluene"] - - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "toluene" - ] - ) -) - -m.fs.R101.conversion.fix(0.75) -m.fs.R101.heat_duty.fix(0) - - -# The Flash conditions for F101 can be set as follows. - -# In[32]: - - -m.fs.F101.vap_outlet.temperature.fix(325.0) -m.fs.F101.deltaP.fix(0) - - -#
-# Inline Exercise: -# Set the conditions for Flash F102 to the following conditions: -#
    -#
  • T = 375 K
  • -#
  • deltaP = -200000
  • -#
-# -# Use Shift+Enter to run the cell once you have typed in your code. -#
- -# In[33]: - - -# Todo: Set conditions for Flash F102 - - -# In[34]: - - -m.fs.F102.vap_outlet.temperature.fix(375) -m.fs.F102.deltaP.fix(-200000) - - -# Let us fix the purge split fraction to 20% and the outlet pressure of the compressor is set to 350000 Pa. - -# In[35]: - - -m.fs.S101.split_fraction[0, "purge"].fix(0.2) -m.fs.C101.outlet.pressure.fix(350000) - - -#
-# Inline Exercise: -# We have now defined all the feed conditions and the inputs required for the unit models. The system should now have 0 degrees of freedom i.e. should be a square problem. Please check that the degrees of freedom is 0. -# -# Use Shift+Enter to run the cell once you have typed in your code. -#
- -# In[36]: - - -# Todo: print the degrees of freedom - - -# In[37]: - - -print(degrees_of_freedom(m)) - - -# In[38]: - - -# Check the degrees of freedom -assert degrees_of_freedom(m) == 0 - - -# ## 5 Initializing the Model -# -# -# -# When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible. -# -# It is important to determine the tear stream for a flowsheet which will be demonstrated below. -# -# -# ![](HDA_tear_stream.png) -# -# Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or -# manually propagating through the flowsheet. The tear stream in this example will be the stream from the mixer to the heater since that is where the -# recycle stream first enters back into the main process. -# -# - -# First, we will highlight some helpful functions that are used in the initialization process. - -# In[39]: - - -def initialize_unit(unit): - from idaes.core.util.exceptions import InitializationError - import idaes.logger as idaeslog - - optarg = { - "OF_ma57_automatic_scaling": "yes", - "max_iter": 1000, - "tol": 1e-8, - } - - try: - initializer = unit.default_initializer(solver_options=optarg) - initializer.initialize(unit, output_level=idaeslog.INFO_LOW) - except InitializationError: - solver = get_solver(solver_options=optarg) - solver.solve(unit) - - -# This first function will take any unit model and can either initialize the model with its respective default -# initializer, or use a generic solver and the solve the current state of the unit model. Often times a direct -# initialization method will fail while a solving method will converge so having the option for both is helpful. -# -# -# ### 5.1 Sequential Decomposition -# -# This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition - -# In[40]: - - -def automatic_propagation(m, tear_guesses): - - from pyomo.network import SequentialDecomposition - - seq = SequentialDecomposition() - seq.options.select_tear_method = "heuristic" - seq.options.tear_method = "Wegstein" - seq.options.iterLim = 5 - - # Using the SD tool - G = seq.create_graph(m) - heuristic_tear_set = seq.tear_set_arcs(G, method="heuristic") - order = seq.calculation_order(G) - - # Pass the tear_guess to the SD tool - seq.set_guesses_for(heuristic_tear_set[0].destination, tear_guesses) - - print(f"Tear Stream starts at: {heuristic_tear_set[0].destination.name}") - - for o in order: - print(o[0].name) - - seq.run(m, initialize_unit) - - -# We are now ready to initialize our flowsheet in a sequential mode. Note that we specifically set the iteration limit -# to be 5 as we are trying to use this tool only to get a good set of initial values such that IPOPT can then take over -# and solve this flowsheet for us. Uncomment this function call to run the automatic propagation method - -# In[41]: - - -# automatic_propagation(m, tear_guesses) - - -# ### 5.2 Manual Propagation Method -# -# This method uses a more direct approach to initialize the flowsheet, using the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly. -# Lets define the function that will help us manually propagate and step through the flowsheet - -# In[42]: - - -def manual_propagation(m, tear_guesses): - from idaes.core.util.initialization import propagate_state - - print(f"The DOF is {degrees_of_freedom(m)} initially") - m.fs.s03_expanded.deactivate() - print(f"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream") - - for k, v in tear_guesses.items(): - for k1, v1 in v.items(): - getattr(m.fs.s03.destination, k)[k1].fix(v1) - - print(f"The DOF is {degrees_of_freedom(m)} after setting the tear stream") - - optarg = { - "OF_ma57_automatic_scaling": "yes", - "max_iter": 300, - # "tol": 1e-10, - } - - solver = get_solver(solver_options=optarg) - - initialize_unit(m.fs.H101) # Initialize Heater - propagate_state(m.fs.s04) # Establish connection between Heater and Reactor - initialize_unit(m.fs.R101) # Initialize Reactor - propagate_state( - m.fs.s05 - ) # Establish connection between Reactor and First Flash Unit - initialize_unit(m.fs.F101) # Initialize First Flash Unit - propagate_state( - m.fs.s06 - ) # Establish connection between First Flash Unit and Splitter - propagate_state( - m.fs.s07 - ) # Establish connection between First Flash Unit and Second Flash Unit - initialize_unit(m.fs.S101) # Initialize Splitter - propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor - initialize_unit(m.fs.C101) # Initialize Compressor - propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer - initialize_unit(m.fs.I101) # Initialize Toluene Inlet - propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer - initialize_unit(m.fs.I102) # Initialize Hydrogen Inlet - propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer - initialize_unit(m.fs.M101) # Initialize Mixer - propagate_state(m.fs.s03) # Establish connection between Mixer and Heater - solver.solve(m.fs.F102) - propagate_state( - m.fs.s10 - ) # Establish connection between Second Flash Unit and Benzene Product - propagate_state( - m.fs.s11 - ) # Establish connection between Second Flash Unit and Toluene Product - propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product - - optarg = { - "OF_ma57_automatic_scaling": "yes", - "max_iter": 300, - "tol": 1e-8, - } - solver = get_solver("ipopt_v2", options=optarg) - solver.solve(m, tee=False) - - for k, v in tear_guesses.items(): - for k1, v1 in v.items(): - getattr(m.fs.H101.inlet, k)[k1].unfix() - - m.fs.s03_expanded.activate() - print( - f"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream" - ) - - -# It will first show that the degrees of freedom is correctly at 0 before any streams are deactivated. Once the tear -# stream is deactivated though, the degrees of freedom will be 10. That means 10 variables will have to be defined with -# the tear guesses `tear_guesses`. Then each unit model can be initialized with our same helper function and then can -# propagate the corresponding connection to the following unit models. At the end, the whole flowsheet is solved, -# giving a much better chance for the recycle stream to be used correctly the flowsheet to converge. - -# In[43]: - - -manual_propagation(m, tear_guesses) - - -# ## 6 Solving the Model - -# We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html - -# In[44]: - - -optarg = { - "OF_ma57_automatic_scaling": "yes", - "max_iter": 300, - "tol": 1e-8, -} - - -#
-# Inline Exercise: -# Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following: -# -# solver = get_solver(solver_options=optarg)
-# results = solver.solve(m, tee=True) -# -# Use Shift+Enter to run the cell once you have typed in your code. -#
-# - -# In[45]: - - -# Create the solver object - -# Solve the model - - -# In[46]: - - -# Create the solver object -solver = get_solver("ipopt_v2", options=optarg) - -# Solve the model -results = solver.solve(m, tee=True) - - -# In[47]: - - -# Check solver solve status -from pyomo.environ import TerminationCondition - -assert results.solver.termination_condition == TerminationCondition.optimal - - -# ## 7 Analyze the results -# -# -# - -# If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window. -# - -# In[48]: - - -# m.fs.visualize("HDA-Flowsheet") - - -# Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display. - -# In[49]: - - -m.fs.report() - - -# What is the total operating cost? - -# In[50]: - - -print("operating cost = $", value(m.fs.operating_cost)) - - -# In[51]: - - -import pytest - -assert value(m.fs.operating_cost) == pytest.approx(419008.28189, rel=1e-6) - - -# For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method. - -# In[52]: - - -m.fs.F102.report() - -print() -print("benzene purity = ", value(m.fs.purity)) - - -# In[53]: - - -assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3) -assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, abs=1e-3) -assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3) - - -# Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101. - -# In[54]: - - -from idaes.core.util.tables import ( - create_stream_table_dataframe, - stream_table_dataframe_to_string, -) - -st = create_stream_table_dataframe({"Reactor": m.fs.s05, "Light Gases": m.fs.s06}) -print(stream_table_dataframe_to_string(st)) - - -# ## 8 Optimization -# -# -# We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\%. However, we are losing around 42\% of benzene in F101 vapor outlet stream. -# -# Let us try to minimize this cost such that: -# - we are producing at least 0.15 mol/s of benzene in F102 vapor outlet i.e. our product stream -# - purity of benzene i.e. the mole fraction of benzene in F102 vapor outlet is at least 80% -# - restricting the benzene loss in F101 vapor outlet to less than 20% -# -# For this problem, our decision variables are as follows: -# - H101 outlet temperature -# - R101 cooling duty provided -# - F101 outlet temperature -# - F102 outlet temperature -# - F102 deltaP in the flash tank -# - -# Let us declare our objective function for this problem. - -# In[55]: - - -m.fs.objective = Objective(expr=m.fs.operating_cost) - - -# Now, we need to unfix the decision variables as we had solved a square problem (degrees of freedom = 0) until now. -# -# Because we are using a stoichiometric reactor, the reactor temperature has no effect on the reaction yield. Additionally, we are using the same cost for heat removal from both the reactor and flash units. Therefore, the optimization algorithm has no reason to prefer heat removal in one place or the other; the solution returned is not locally unique. To remove this indeterminancy and ensure that a consistent solution is returned, we fix the outlet temperature of the reactor. - -# In[56]: - - -m.fs.H101.outlet.temperature.unfix() -m.fs.R101.heat_duty.unfix() -m.fs.R101.outlet.temperature.fix(600) -m.fs.F101.vap_outlet.temperature.unfix() -m.fs.F102.vap_outlet.temperature.unfix() - - -#
-# Inline Exercise: -# Let us now unfix the remaining variable which is F102 pressure drop (F102.deltaP) -# -# Use Shift+Enter to run the cell once you have typed in your code. -#
-# -# - -# In[57]: - - -# Todo: Unfix deltaP for F102 - - -# In[58]: - - -# Todo: Unfix deltaP for F102 -m.fs.F102.deltaP.unfix() - - -# In[59]: - - -assert degrees_of_freedom(m) == 4 - - -# Next, we need to set bounds on these decision variables to values shown below: -# -# - H101 outlet temperature [500, 600] K -# - F101 outlet temperature [298, 450] K -# - F102 outlet temperature [298, 450] K -# - F102 outlet pressure [105000, 110000] Pa -# -# Let us first set the variable bound for the H101 outlet temperature as shown below: - -# In[60]: - - -m.fs.H101.outlet.temperature[0].setlb(500) -m.fs.H101.outlet.temperature[0].setub(600) - - -#
-# Inline Exercise: -# Now, set the variable bound for the F101 outlet temperature. -# -# Use Shift+Enter to run the cell once you have typed in your code. -#
- -# In[61]: - - -# Todo: Set the bounds for flash 101 outlet temperature - - -# In[62]: - - -# Todo: Set the bounds for reactor outlet temperature -m.fs.F101.vap_outlet.temperature[0].setlb(298.0) -m.fs.F101.vap_outlet.temperature[0].setub(450.0) - - -# Let us fix the bounds for the rest of the decision variables. - -# In[63]: - - -m.fs.F102.vap_outlet.temperature[0].setlb(298.0) -m.fs.F102.vap_outlet.temperature[0].setub(450.0) -m.fs.F102.vap_outlet.pressure[0].setlb(105000) -m.fs.F102.vap_outlet.pressure[0].setub(110000) - - -# Now, the only things left to define are our constraints on overhead loss in F101, product flow rate and purity in F102. Let us first look at defining a constraint for the overhead loss in F101 where we are restricting the benzene leaving the vapor stream to less than 20 \% of the benzene available in the reactor outlet. - -# In[64]: - - -m.fs.overhead_loss = Constraint( - expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" - ] - <= 0.20 - * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp["Vap", "benzene"] -) - - -#
-# Inline Exercise: -# Now, add the constraint such that we are producing at least 0.15 mol/s of benzene in the product stream which is the vapor outlet of F102. Let us name this constraint as m.fs.product_flow. -# -# Use Shift+Enter to run the cell once you have typed in your code. -#
- -# In[65]: - - -# Todo: Add minimum product flow constraint - - -# In[66]: - - -# Todo: Add minimum product flow constraint -m.fs.product_flow = Constraint( - expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ - "Vap", "benzene" - ] - >= 0.15 -) - - -# Let us add the final constraint on product purity or the mole fraction of benzene in the product stream such that it is at least greater than 80%. - -# In[67]: - - -m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80) - - -# -# We have now defined the optimization problem and we are now ready to solve this problem. -# -# -# - -# In[68]: - - -results = solver.solve(m, tee=False) - - -# In[69]: - - -# Check for solver solve status -from pyomo.environ import TerminationCondition - -assert results.solver.termination_condition == TerminationCondition.optimal - - -# ### 8.1 Optimization Results -# -# Display the results and product specifications - -# In[70]: - - -print("operating cost = $", value(m.fs.operating_cost)) - -print() -print("Product flow rate and purity in F102") - -m.fs.F102.report() - -print() -print("benzene purity = ", value(m.fs.purity)) - -print() -print("Overhead loss in F101") -m.fs.F101.report() - - -# In[71]: - - -assert value(m.fs.operating_cost) == pytest.approx(312674.236, rel=1e-4) -assert value(m.fs.purity) == pytest.approx(0.818827, rel=1e-4) - - -# Display optimal values for the decision variables - -# In[72]: - - -print( - f"""Optimal Values: - -H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K - -R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W - -F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K - -F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K -F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa -""" -) - - -# In[73]: - - -assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, rel=1e-4) -assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, rel=1e-4) -assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, rel=1e-4) -assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, rel=1e-4) -assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, rel=1e-4) - diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb index e219ec93..4950760f 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb @@ -2,16 +2,18 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "metadata": { - "tags": [ - "header", - "hide-cell" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:01.286374300Z", "start_time": "2026-02-25T17:35:01.274737700Z" - } + }, + "tags": [ + "header", + "hide-cell" + ] }, + "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -25,9 +27,7 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -119,12 +119,14 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:01.830457200Z", "start_time": "2026-02-25T17:35:01.290402400Z" } }, + "outputs": [], "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -136,9 +138,7 @@ " value,\n", ")\n", "from pyomo.network import Arc" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -157,24 +157,28 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.665835Z", "start_time": "2026-02-25T17:35:01.832975100Z" } }, - "source": "from idaes.core import FlowsheetBlock", "outputs": [], - "execution_count": 3 + "source": [ + "from idaes.core import FlowsheetBlock" + ] }, { "cell_type": "code", + "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.734656600Z", "start_time": "2026-02-25T17:35:03.667871Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -185,9 +189,7 @@ " Feed,\n", " Product,\n", ")" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -201,21 +203,21 @@ }, { "cell_type": "code", + "execution_count": 6, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.752580Z", "start_time": "2026-02-25T17:35:03.745137800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -226,21 +228,21 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.761528300Z", "start_time": "2026-02-25T17:35:03.753588300Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", "from idaes.core.solvers import get_solver" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -261,13 +263,15 @@ ] }, { + "cell_type": "code", + "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.838559500Z", "start_time": "2026-02-25T17:35:03.761528300Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "from idaes.models.properties.modular_properties.base.generic_property import (\n", " GenericParameterBlock,\n", @@ -277,9 +281,7 @@ ")\n", "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -292,18 +294,18 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.849781Z", "start_time": "2026-02-25T17:35:03.841636100Z" } }, + "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "markdown", @@ -314,20 +316,20 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.879447Z", "start_time": "2026-02-25T17:35:03.851130600Z" } }, + "outputs": [], "source": [ "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", "m.fs.reaction_params = GenericReactionParameterBlock(\n", " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -340,12 +342,14 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.925685100Z", "start_time": "2026-02-25T17:35:03.881771100Z" } }, + "outputs": [], "source": [ "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", @@ -360,21 +364,21 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ], - "outputs": [], - "execution_count": 11 + ] }, { "cell_type": "code", + "execution_count": 13, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.956022500Z", "start_time": "2026-02-25T17:35:03.935614400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -384,9 +388,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ], - "outputs": [], - "execution_count": 13 + ] }, { "cell_type": "markdown", @@ -402,21 +404,21 @@ }, { "cell_type": "code", + "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.979104400Z", "start_time": "2026-02-25T17:35:03.958076200Z" } }, + "outputs": [], "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "markdown", @@ -427,12 +429,14 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.031371300Z", "start_time": "2026-02-25T17:35:03.981638100Z" } }, + "outputs": [], "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -452,9 +456,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 15 + ] }, { "cell_type": "markdown", @@ -465,19 +467,19 @@ }, { "cell_type": "code", + "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.049278900Z", "start_time": "2026-02-25T17:35:04.033910400Z" } }, + "outputs": [], "source": [ "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ], - "outputs": [], - "execution_count": 16 + ] }, { "cell_type": "markdown", @@ -497,37 +499,37 @@ }, { "cell_type": "code", + "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.059097Z", "start_time": "2026-02-25T17:35:04.051649500Z" } }, + "outputs": [], "source": [ "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ], - "outputs": [], - "execution_count": 17 + ] }, { "cell_type": "code", + "execution_count": 19, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.074873700Z", "start_time": "2026-02-25T17:35:04.067198800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ], - "outputs": [], - "execution_count": 19 + ] }, { "cell_type": "markdown", @@ -538,21 +540,21 @@ }, { "cell_type": "code", + "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.082717500Z", "start_time": "2026-02-25T17:35:04.075379Z" } }, + "outputs": [], "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ], - "outputs": [], - "execution_count": 20 + ] }, { "cell_type": "markdown", @@ -563,19 +565,19 @@ }, { "cell_type": "code", + "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.091461Z", "start_time": "2026-02-25T17:35:04.083716700Z" } }, + "outputs": [], "source": [ "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ], - "outputs": [], - "execution_count": 21 + ] }, { "cell_type": "markdown", @@ -586,17 +588,17 @@ }, { "cell_type": "code", + "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.116142500Z", "start_time": "2026-02-25T17:35:04.092591700Z" } }, + "outputs": [], "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ], - "outputs": [], - "execution_count": 22 + ] }, { "cell_type": "markdown", @@ -618,12 +620,14 @@ }, { "cell_type": "code", + "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.126991900Z", "start_time": "2026-02-25T17:35:04.118294Z" } }, + "outputs": [], "source": [ "m.fs.purity = Expression(\n", " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -636,9 +640,7 @@ " ]\n", " )\n", ")" - ], - "outputs": [], - "execution_count": 23 + ] }, { "cell_type": "markdown", @@ -649,19 +651,19 @@ }, { "cell_type": "code", + "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.134981600Z", "start_time": "2026-02-25T17:35:04.126991900Z" } }, + "outputs": [], "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ], - "outputs": [], - "execution_count": 24 + ] }, { "cell_type": "markdown", @@ -678,19 +680,19 @@ }, { "cell_type": "code", + "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.142918500Z", "start_time": "2026-02-25T17:35:04.134981600Z" } }, + "outputs": [], "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ], - "outputs": [], - "execution_count": 25 + ] }, { "cell_type": "markdown", @@ -701,19 +703,19 @@ }, { "cell_type": "code", + "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.151633300Z", "start_time": "2026-02-25T17:35:04.143918400Z" } }, + "outputs": [], "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ], - "outputs": [], - "execution_count": 26 + ] }, { "cell_type": "markdown", @@ -727,15 +729,13 @@ }, { "cell_type": "code", + "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.183600800Z", "start_time": "2026-02-25T17:35:04.152655800Z" } }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -745,7 +745,9 @@ ] } ], - "execution_count": 27 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "markdown", @@ -759,19 +761,19 @@ }, { "cell_type": "code", + "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.227743300Z", "start_time": "2026-02-25T17:35:04.218810900Z" } }, + "outputs": [], "source": [ "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", "\n", "tear_guesses = fix_inlet_states(m)" - ], - "outputs": [], - "execution_count": 29 + ] }, { "cell_type": "markdown", @@ -784,17 +786,17 @@ }, { "cell_type": "code", + "execution_count": 30, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.235882200Z", "start_time": "2026-02-25T17:35:04.227743300Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ], - "outputs": [], - "execution_count": 30 + ] }, { "cell_type": "markdown", @@ -805,12 +807,14 @@ }, { "cell_type": "code", + "execution_count": 31, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.257770300Z", "start_time": "2026-02-25T17:35:04.236888500Z" } }, + "outputs": [], "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", @@ -827,9 +831,7 @@ "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ], - "outputs": [], - "execution_count": 31 + ] }, { "cell_type": "markdown", @@ -840,36 +842,36 @@ }, { "cell_type": "code", + "execution_count": 32, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.268846Z", "start_time": "2026-02-25T17:35:04.260299600Z" } }, + "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ], - "outputs": [], - "execution_count": 32 + ] }, { "cell_type": "code", + "execution_count": 34, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.288481300Z", "start_time": "2026-02-25T17:35:04.279196300Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ], - "outputs": [], - "execution_count": 34 + ] }, { "cell_type": "markdown", @@ -880,33 +882,31 @@ }, { "cell_type": "code", + "execution_count": 35, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.302496300Z", "start_time": "2026-02-25T17:35:04.289482700Z" } }, + "outputs": [], "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ], - "outputs": [], - "execution_count": 35 + ] }, { "cell_type": "code", + "execution_count": 37, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.340811100Z", "start_time": "2026-02-25T17:35:04.313761800Z" - } + }, + "tags": [ + "solution" + ] }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -916,7 +916,9 @@ ] } ], - "execution_count": 37 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "markdown", @@ -940,25 +942,28 @@ ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "First, we will highlight some helpful functions that are used in the initialization process." + "metadata": {}, + "source": [ + "First, we will highlight some helpful functions that are used in the initialization process." + ] }, { + "cell_type": "code", + "execution_count": 39, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.386344500Z", "start_time": "2026-02-25T17:35:04.376804600Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def initialize_unit(unit):\n", " from idaes.core.util.exceptions import InitializationError\n", " import idaes.logger as idaeslog\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", @@ -970,9 +975,7 @@ " except InitializationError:\n", " solver = get_solver(solver_options=optarg)\n", " solver.solve(unit)" - ], - "outputs": [], - "execution_count": 39 + ] }, { "cell_type": "markdown", @@ -989,13 +992,15 @@ ] }, { + "cell_type": "code", + "execution_count": 40, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.394802500Z", "start_time": "2026-02-25T17:35:04.386344500Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def automatic_propagation(m, tear_guesses):\n", "\n", @@ -1020,9 +1025,7 @@ " print(o[0].name)\n", "\n", " seq.run(m, initialize_unit)" - ], - "outputs": [], - "execution_count": 40 + ] }, { "cell_type": "markdown", @@ -1034,16 +1037,18 @@ ] }, { + "cell_type": "code", + "execution_count": 41, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.404491500Z", "start_time": "2026-02-25T17:35:04.396317500Z" } }, - "cell_type": "code", - "source": "# automatic_propagation(m, tear_guesses)", "outputs": [], - "execution_count": 41 + "source": [ + "# automatic_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1057,12 +1062,14 @@ }, { "cell_type": "code", + "execution_count": 42, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.417815100Z", "start_time": "2026-02-25T17:35:04.404995800Z" } }, + "outputs": [], "source": [ "def manual_propagation(m, tear_guesses):\n", " from idaes.core.util.initialization import propagate_state\n", @@ -1078,7 +1085,6 @@ " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " # \"tol\": 1e-10,\n", @@ -1119,7 +1125,6 @@ " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " \"tol\": 1e-8,\n", @@ -1135,9 +1140,7 @@ " print(\n", " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", " )" - ], - "outputs": [], - "execution_count": 42 + ] }, { "cell_type": "markdown", @@ -1152,13 +1155,13 @@ }, { "cell_type": "code", + "execution_count": 43, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.145125500Z", "start_time": "2026-02-25T17:35:04.419335500Z" } }, - "source": "manual_propagation(m, tear_guesses)", "outputs": [ { "name": "stdout", @@ -1171,7 +1174,9 @@ ] } ], - "execution_count": 43 + "source": [ + "manual_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1191,43 +1196,42 @@ }, { "cell_type": "code", + "execution_count": 44, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.161129400Z", "start_time": "2026-02-25T17:35:07.146644300Z" } }, + "outputs": [], "source": [ "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", "}" - ], - "outputs": [], - "execution_count": 44 + ] }, { "cell_type": "code", + "execution_count": 46, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.272798500Z", "start_time": "2026-02-25T17:35:07.170980400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=False)" - ], - "outputs": [], - "execution_count": 46 + ] }, { "cell_type": "markdown", @@ -1254,15 +1258,13 @@ }, { "cell_type": "code", + "execution_count": 49, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.337983600Z", "start_time": "2026-02-25T17:35:07.303479400Z" } }, - "source": [ - "m.fs.report()" - ], "outputs": [ { "name": "stdout", @@ -1274,21 +1276,23 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 1.6736e-09 1.8681e-09 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7852e-07\n", " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.8212e-08 1.8212e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.8268e-08 4.8268e-08 0.72074\n", " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", "====================================================================================\n" ] } ], - "execution_count": 49 + "source": [ + "m.fs.report()" + ] }, { "cell_type": "markdown", @@ -1299,25 +1303,25 @@ }, { "cell_type": "code", + "execution_count": 50, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.355013500Z", "start_time": "2026-02-25T17:35:07.346055600Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 419008.28211932775\n" + "operating cost = $ 419008.28599155403\n" ] } ], - "execution_count": 50 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ] }, { "cell_type": "markdown", @@ -1328,18 +1332,13 @@ }, { "cell_type": "code", + "execution_count": 52, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.469810Z", "start_time": "2026-02-25T17:35:07.452663800Z" } }, - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ], "outputs": [ { "name": "stdout", @@ -1360,33 +1359,28 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", + " flow_mol_phase Liq mole / second 0.26712 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.76595 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.23405 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.084499 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0088437 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18592 1.8212e-08 1.8212e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.72074 4.8268e-08 4.8268e-08 \n", + " temperature kelvin 325.00 375.00 375.00 \n", + " pressure pascal 3.5000e+05 1.5000e+05 1.5000e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.8242963521555953\n" + "benzene purity = 0.8242963399526197\n" ] } ], - "execution_count": 52 + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ] }, { "cell_type": "markdown", @@ -1397,28 +1391,20 @@ }, { "cell_type": "code", + "execution_count": 54, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.503351300Z", "start_time": "2026-02-25T17:35:07.487979400Z" } }, - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Liq mole / second 1.8681e-09 1.0000e-08 \n", "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", @@ -1431,7 +1417,15 @@ ] } ], - "execution_count": 54 + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ] }, { "cell_type": "markdown", @@ -1464,17 +1458,17 @@ }, { "cell_type": "code", + "execution_count": 55, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.523495700Z", "start_time": "2026-02-25T17:35:07.513232100Z" } }, + "outputs": [], "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ], - "outputs": [], - "execution_count": 55 + ] }, { "cell_type": "markdown", @@ -1487,39 +1481,39 @@ }, { "cell_type": "code", + "execution_count": 56, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.538051100Z", "start_time": "2026-02-25T17:35:07.528058900Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.R101.outlet.temperature.fix(600)\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ], - "outputs": [], - "execution_count": 56 + ] }, { "cell_type": "code", + "execution_count": 58, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.578318700Z", "start_time": "2026-02-25T17:35:07.571295800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ], - "outputs": [], - "execution_count": 58 + ] }, { "cell_type": "markdown", @@ -1537,37 +1531,37 @@ }, { "cell_type": "code", + "execution_count": 60, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.627054600Z", "start_time": "2026-02-25T17:35:07.619525700Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ], - "outputs": [], - "execution_count": 60 + ] }, { "cell_type": "code", + "execution_count": 62, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.652892600Z", "start_time": "2026-02-25T17:35:07.643756900Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" - ], - "outputs": [], - "execution_count": 62 + ] }, { "cell_type": "markdown", @@ -1578,20 +1572,20 @@ }, { "cell_type": "code", + "execution_count": 63, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.662831700Z", "start_time": "2026-02-25T17:35:07.654919400Z" } }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ], - "outputs": [], - "execution_count": 63 + ] }, { "cell_type": "markdown", @@ -1602,12 +1596,14 @@ }, { "cell_type": "code", + "execution_count": 64, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.673507300Z", "start_time": "2026-02-25T17:35:07.666381200Z" } }, + "outputs": [], "source": [ "m.fs.overhead_loss = Constraint(\n", " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -1616,21 +1612,21 @@ " <= 0.20\n", " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ], - "outputs": [], - "execution_count": 64 + ] }, { "cell_type": "code", + "execution_count": 66, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.707964Z", "start_time": "2026-02-25T17:35:07.699126100Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", @@ -1639,9 +1635,7 @@ " ]\n", " >= 0.15\n", ")" - ], - "outputs": [], - "execution_count": 66 + ] }, { "cell_type": "markdown", @@ -1652,17 +1646,17 @@ }, { "cell_type": "code", + "execution_count": 67, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.718982700Z", "start_time": "2026-02-25T17:35:07.711201900Z" } }, + "outputs": [], "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ], - "outputs": [], - "execution_count": 67 + ] }, { "cell_type": "markdown", @@ -1676,15 +1670,17 @@ }, { "cell_type": "code", + "execution_count": 68, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.837157700Z", "start_time": "2026-02-25T17:35:07.721454600Z" } }, - "source": "results = solver.solve(m, tee=False)", "outputs": [], - "execution_count": 68 + "source": [ + "results = solver.solve(m, tee=False)" + ] }, { "cell_type": "markdown", @@ -1697,33 +1693,19 @@ }, { "cell_type": "code", + "execution_count": 70, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.883912Z", "start_time": "2026-02-25T17:35:07.847804400Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 312674.2367538264\n", + "operating cost = $ 312674.23682387645\n", "\n", "Product flow rate and purity in F102\n", "\n", @@ -1741,29 +1723,19 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", + " flow_mol_phase Liq mole / second 0.28812 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.75463 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.24537 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.032748 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0032478 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.21614 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.74786 4.0825e-08 4.0825e-08 \n", + " temperature kelvin 301.88 362.93 362.93 \n", + " pressure pascal 3.5000e+05 1.0500e+05 1.0500e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.818829588839798\n", + "benzene purity = 0.8188295887582271\n", "\n", "Overhead loss in F101\n", "\n", @@ -1781,31 +1753,35 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", + " flow_mol_phase Liq mole / second 2.6866e-12 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second 1.9480 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.57381 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.42619 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.13952 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.039059 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18417 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.63725 0.74786 0.74786 \n", + " temperature kelvin 600.00 301.88 301.88 \n", + " pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 \n", "====================================================================================\n" ] } ], - "execution_count": 70 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ] }, { "cell_type": "markdown", @@ -1816,27 +1792,13 @@ }, { "cell_type": "code", + "execution_count": 72, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.924695400Z", "start_time": "2026-02-25T17:35:07.893574600Z" } }, - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ], "outputs": [ { "name": "stdout", @@ -1856,7 +1818,21 @@ ] } ], - "execution_count": 72 + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ] } ], "metadata": { @@ -1876,7 +1852,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.12.0" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb index 33e47e7a..53deb6c5 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb @@ -2,16 +2,18 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "metadata": { - "tags": [ - "header", - "hide-cell" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:01.286374300Z", "start_time": "2026-02-25T17:35:01.274737700Z" - } + }, + "tags": [ + "header", + "hide-cell" + ] }, + "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -25,9 +27,7 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -119,12 +119,14 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:01.830457200Z", "start_time": "2026-02-25T17:35:01.290402400Z" } }, + "outputs": [], "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -136,9 +138,7 @@ " value,\n", ")\n", "from pyomo.network import Arc" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -157,24 +157,28 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.665835Z", "start_time": "2026-02-25T17:35:01.832975100Z" } }, - "source": "from idaes.core import FlowsheetBlock", "outputs": [], - "execution_count": 3 + "source": [ + "from idaes.core import FlowsheetBlock" + ] }, { "cell_type": "code", + "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.734656600Z", "start_time": "2026-02-25T17:35:03.667871Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -185,9 +189,7 @@ " Feed,\n", " Product,\n", ")" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -201,20 +203,20 @@ }, { "cell_type": "code", + "execution_count": 5, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.744136400Z", "start_time": "2026-02-25T17:35:03.736701700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ], - "outputs": [], - "execution_count": 5 + ] }, { "cell_type": "markdown", @@ -225,21 +227,21 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.761528300Z", "start_time": "2026-02-25T17:35:03.753588300Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", "from idaes.core.solvers import get_solver" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -260,13 +262,15 @@ ] }, { + "cell_type": "code", + "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.838559500Z", "start_time": "2026-02-25T17:35:03.761528300Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "from idaes.models.properties.modular_properties.base.generic_property import (\n", " GenericParameterBlock,\n", @@ -276,9 +280,7 @@ ")\n", "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -291,18 +293,18 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.849781Z", "start_time": "2026-02-25T17:35:03.841636100Z" } }, + "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "markdown", @@ -313,20 +315,20 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.879447Z", "start_time": "2026-02-25T17:35:03.851130600Z" } }, + "outputs": [], "source": [ "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", "m.fs.reaction_params = GenericReactionParameterBlock(\n", " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -339,12 +341,14 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.925685100Z", "start_time": "2026-02-25T17:35:03.881771100Z" } }, + "outputs": [], "source": [ "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", @@ -359,9 +363,7 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ], - "outputs": [], - "execution_count": 11 + ] }, { "cell_type": "markdown", @@ -386,20 +388,20 @@ }, { "cell_type": "code", + "execution_count": 12, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.935108600Z", "start_time": "2026-02-25T17:35:03.927715700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ], - "outputs": [], - "execution_count": 12 + ] }, { "cell_type": "markdown", @@ -415,21 +417,21 @@ }, { "cell_type": "code", + "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.979104400Z", "start_time": "2026-02-25T17:35:03.958076200Z" } }, + "outputs": [], "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "markdown", @@ -440,12 +442,14 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.031371300Z", "start_time": "2026-02-25T17:35:03.981638100Z" } }, + "outputs": [], "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -465,9 +469,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 15 + ] }, { "cell_type": "markdown", @@ -478,19 +480,19 @@ }, { "cell_type": "code", + "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.049278900Z", "start_time": "2026-02-25T17:35:04.033910400Z" } }, + "outputs": [], "source": [ "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ], - "outputs": [], - "execution_count": 16 + ] }, { "cell_type": "markdown", @@ -510,19 +512,19 @@ }, { "cell_type": "code", + "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.059097Z", "start_time": "2026-02-25T17:35:04.051649500Z" } }, + "outputs": [], "source": [ "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ], - "outputs": [], - "execution_count": 17 + ] }, { "cell_type": "markdown", @@ -540,20 +542,20 @@ }, { "cell_type": "code", + "execution_count": 18, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.067198800Z", "start_time": "2026-02-25T17:35:04.059097Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ], - "outputs": [], - "execution_count": 18 + ] }, { "cell_type": "markdown", @@ -564,21 +566,21 @@ }, { "cell_type": "code", + "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.082717500Z", "start_time": "2026-02-25T17:35:04.075379Z" } }, + "outputs": [], "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ], - "outputs": [], - "execution_count": 20 + ] }, { "cell_type": "markdown", @@ -589,19 +591,19 @@ }, { "cell_type": "code", + "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.091461Z", "start_time": "2026-02-25T17:35:04.083716700Z" } }, + "outputs": [], "source": [ "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ], - "outputs": [], - "execution_count": 21 + ] }, { "cell_type": "markdown", @@ -612,17 +614,17 @@ }, { "cell_type": "code", + "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.116142500Z", "start_time": "2026-02-25T17:35:04.092591700Z" } }, + "outputs": [], "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ], - "outputs": [], - "execution_count": 22 + ] }, { "cell_type": "markdown", @@ -644,12 +646,14 @@ }, { "cell_type": "code", + "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.126991900Z", "start_time": "2026-02-25T17:35:04.118294Z" } }, + "outputs": [], "source": [ "m.fs.purity = Expression(\n", " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -662,9 +666,7 @@ " ]\n", " )\n", ")" - ], - "outputs": [], - "execution_count": 23 + ] }, { "cell_type": "markdown", @@ -675,19 +677,19 @@ }, { "cell_type": "code", + "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.134981600Z", "start_time": "2026-02-25T17:35:04.126991900Z" } }, + "outputs": [], "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ], - "outputs": [], - "execution_count": 24 + ] }, { "cell_type": "markdown", @@ -704,19 +706,19 @@ }, { "cell_type": "code", + "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.142918500Z", "start_time": "2026-02-25T17:35:04.134981600Z" } }, + "outputs": [], "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ], - "outputs": [], - "execution_count": 25 + ] }, { "cell_type": "markdown", @@ -727,19 +729,19 @@ }, { "cell_type": "code", + "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.151633300Z", "start_time": "2026-02-25T17:35:04.143918400Z" } }, + "outputs": [], "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ], - "outputs": [], - "execution_count": 26 + ] }, { "cell_type": "markdown", @@ -753,15 +755,13 @@ }, { "cell_type": "code", + "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.183600800Z", "start_time": "2026-02-25T17:35:04.152655800Z" } }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -771,7 +771,9 @@ ] } ], - "execution_count": 27 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "markdown", @@ -785,19 +787,19 @@ }, { "cell_type": "code", + "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.227743300Z", "start_time": "2026-02-25T17:35:04.218810900Z" } }, + "outputs": [], "source": [ "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", "\n", "tear_guesses = fix_inlet_states(m)" - ], - "outputs": [], - "execution_count": 29 + ] }, { "cell_type": "markdown", @@ -810,17 +812,17 @@ }, { "cell_type": "code", + "execution_count": 30, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.235882200Z", "start_time": "2026-02-25T17:35:04.227743300Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ], - "outputs": [], - "execution_count": 30 + ] }, { "cell_type": "markdown", @@ -831,12 +833,14 @@ }, { "cell_type": "code", + "execution_count": 31, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.257770300Z", "start_time": "2026-02-25T17:35:04.236888500Z" } }, + "outputs": [], "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", @@ -853,9 +857,7 @@ "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ], - "outputs": [], - "execution_count": 31 + ] }, { "cell_type": "markdown", @@ -866,18 +868,18 @@ }, { "cell_type": "code", + "execution_count": 32, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.268846Z", "start_time": "2026-02-25T17:35:04.260299600Z" } }, + "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ], - "outputs": [], - "execution_count": 32 + ] }, { "cell_type": "markdown", @@ -901,20 +903,20 @@ }, { "cell_type": "code", + "execution_count": 33, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.278171500Z", "start_time": "2026-02-25T17:35:04.269857200Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ], - "outputs": [], - "execution_count": 33 + ] }, { "cell_type": "markdown", @@ -925,18 +927,18 @@ }, { "cell_type": "code", + "execution_count": 35, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.302496300Z", "start_time": "2026-02-25T17:35:04.289482700Z" } }, + "outputs": [], "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ], - "outputs": [], - "execution_count": 35 + ] }, { "cell_type": "markdown", @@ -956,20 +958,20 @@ }, { "cell_type": "code", + "execution_count": 36, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.312730200Z", "start_time": "2026-02-25T17:35:04.305395100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ], - "outputs": [], - "execution_count": 36 + ] }, { "cell_type": "markdown", @@ -993,25 +995,28 @@ ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "First, we will highlight some helpful functions that are used in the initialization process." + "metadata": {}, + "source": [ + "First, we will highlight some helpful functions that are used in the initialization process." + ] }, { + "cell_type": "code", + "execution_count": 39, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.386344500Z", "start_time": "2026-02-25T17:35:04.376804600Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def initialize_unit(unit):\n", " from idaes.core.util.exceptions import InitializationError\n", " import idaes.logger as idaeslog\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", @@ -1023,9 +1028,7 @@ " except InitializationError:\n", " solver = get_solver(solver_options=optarg)\n", " solver.solve(unit)" - ], - "outputs": [], - "execution_count": 39 + ] }, { "cell_type": "markdown", @@ -1042,13 +1045,15 @@ ] }, { + "cell_type": "code", + "execution_count": 40, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.394802500Z", "start_time": "2026-02-25T17:35:04.386344500Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def automatic_propagation(m, tear_guesses):\n", "\n", @@ -1073,9 +1078,7 @@ " print(o[0].name)\n", "\n", " seq.run(m, initialize_unit)" - ], - "outputs": [], - "execution_count": 40 + ] }, { "cell_type": "markdown", @@ -1087,16 +1090,18 @@ ] }, { + "cell_type": "code", + "execution_count": 41, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.404491500Z", "start_time": "2026-02-25T17:35:04.396317500Z" } }, - "cell_type": "code", - "source": "# automatic_propagation(m, tear_guesses)", "outputs": [], - "execution_count": 41 + "source": [ + "# automatic_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1110,12 +1115,14 @@ }, { "cell_type": "code", + "execution_count": 42, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.417815100Z", "start_time": "2026-02-25T17:35:04.404995800Z" } }, + "outputs": [], "source": [ "def manual_propagation(m, tear_guesses):\n", " from idaes.core.util.initialization import propagate_state\n", @@ -1131,7 +1138,6 @@ " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " # \"tol\": 1e-10,\n", @@ -1172,7 +1178,6 @@ " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " \"tol\": 1e-8,\n", @@ -1188,9 +1193,7 @@ " print(\n", " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", " )" - ], - "outputs": [], - "execution_count": 42 + ] }, { "cell_type": "markdown", @@ -1205,13 +1208,13 @@ }, { "cell_type": "code", + "execution_count": 43, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.145125500Z", "start_time": "2026-02-25T17:35:04.419335500Z" } }, - "source": "manual_propagation(m, tear_guesses)", "outputs": [ { "name": "stdout", @@ -1224,7 +1227,9 @@ ] } ], - "execution_count": 43 + "source": [ + "manual_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1244,22 +1249,21 @@ }, { "cell_type": "code", + "execution_count": 44, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.161129400Z", "start_time": "2026-02-25T17:35:07.146644300Z" } }, + "outputs": [], "source": [ "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", "}" - ], - "outputs": [], - "execution_count": 44 + ] }, { "cell_type": "markdown", @@ -1282,22 +1286,22 @@ }, { "cell_type": "code", + "execution_count": 45, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.170980400Z", "start_time": "2026-02-25T17:35:07.163178100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "\n", "# Solve the model" - ], - "outputs": [], - "execution_count": 45 + ] }, { "cell_type": "markdown", @@ -1317,20 +1321,20 @@ }, { "cell_type": "code", + "execution_count": 48, "metadata": { - "tags": [ - "noauto" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.302463Z", "start_time": "2026-02-25T17:35:07.282944100Z" - } + }, + "tags": [ + "noauto" + ] }, + "outputs": [], "source": [ "# m.fs.visualize(\"HDA-Flowsheet\")" - ], - "outputs": [], - "execution_count": 48 + ] }, { "cell_type": "markdown", @@ -1341,15 +1345,13 @@ }, { "cell_type": "code", + "execution_count": 49, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.337983600Z", "start_time": "2026-02-25T17:35:07.303479400Z" } }, - "source": [ - "m.fs.report()" - ], "outputs": [ { "name": "stdout", @@ -1361,21 +1363,23 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 1.6736e-09 1.8681e-09 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7852e-07\n", " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.8212e-08 1.8212e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.8268e-08 4.8268e-08 0.72074\n", " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", "====================================================================================\n" ] } ], - "execution_count": 49 + "source": [ + "m.fs.report()" + ] }, { "cell_type": "markdown", @@ -1386,25 +1390,25 @@ }, { "cell_type": "code", + "execution_count": 50, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.355013500Z", "start_time": "2026-02-25T17:35:07.346055600Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 419008.28211932775\n" + "operating cost = $ 419008.28599155403\n" ] } ], - "execution_count": 50 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ] }, { "cell_type": "markdown", @@ -1415,18 +1419,13 @@ }, { "cell_type": "code", + "execution_count": 52, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.469810Z", "start_time": "2026-02-25T17:35:07.452663800Z" } }, - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ], "outputs": [ { "name": "stdout", @@ -1447,33 +1446,28 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", + " flow_mol_phase Liq mole / second 0.26712 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.76595 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.23405 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.084499 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0088437 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18592 1.8212e-08 1.8212e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.72074 4.8268e-08 4.8268e-08 \n", + " temperature kelvin 325.00 375.00 375.00 \n", + " pressure pascal 3.5000e+05 1.5000e+05 1.5000e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.8242963521555953\n" + "benzene purity = 0.8242963399526197\n" ] } ], - "execution_count": 52 + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ] }, { "cell_type": "markdown", @@ -1484,28 +1478,20 @@ }, { "cell_type": "code", + "execution_count": 54, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.503351300Z", "start_time": "2026-02-25T17:35:07.487979400Z" } }, - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Liq mole / second 1.8681e-09 1.0000e-08 \n", "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", @@ -1518,7 +1504,15 @@ ] } ], - "execution_count": 54 + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ] }, { "cell_type": "markdown", @@ -1551,17 +1545,17 @@ }, { "cell_type": "code", + "execution_count": 55, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.523495700Z", "start_time": "2026-02-25T17:35:07.513232100Z" } }, + "outputs": [], "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ], - "outputs": [], - "execution_count": 55 + ] }, { "cell_type": "markdown", @@ -1574,21 +1568,21 @@ }, { "cell_type": "code", + "execution_count": 56, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.538051100Z", "start_time": "2026-02-25T17:35:07.528058900Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.R101.outlet.temperature.fix(600)\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ], - "outputs": [], - "execution_count": 56 + ] }, { "cell_type": "markdown", @@ -1609,20 +1603,20 @@ }, { "cell_type": "code", + "execution_count": 57, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.568196100Z", "start_time": "2026-02-25T17:35:07.545899Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ], - "outputs": [], - "execution_count": 57 + ] }, { "cell_type": "markdown", @@ -1640,18 +1634,18 @@ }, { "cell_type": "code", + "execution_count": 60, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.627054600Z", "start_time": "2026-02-25T17:35:07.619525700Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ], - "outputs": [], - "execution_count": 60 + ] }, { "cell_type": "markdown", @@ -1671,18 +1665,20 @@ }, { "cell_type": "code", + "execution_count": 61, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.638684200Z", "start_time": "2026-02-25T17:35:07.630104900Z" - } + }, + "tags": [ + "exercise" + ] }, - "source": "# Todo: Set the bounds for flash 101 outlet temperature", "outputs": [], - "execution_count": 61 + "source": [ + "# Todo: Set the bounds for flash 101 outlet temperature" + ] }, { "cell_type": "markdown", @@ -1693,20 +1689,20 @@ }, { "cell_type": "code", + "execution_count": 63, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.662831700Z", "start_time": "2026-02-25T17:35:07.654919400Z" } }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ], - "outputs": [], - "execution_count": 63 + ] }, { "cell_type": "markdown", @@ -1717,12 +1713,14 @@ }, { "cell_type": "code", + "execution_count": 64, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.673507300Z", "start_time": "2026-02-25T17:35:07.666381200Z" } }, + "outputs": [], "source": [ "m.fs.overhead_loss = Constraint(\n", " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -1731,9 +1729,7 @@ " <= 0.20\n", " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ], - "outputs": [], - "execution_count": 64 + ] }, { "cell_type": "markdown", @@ -1753,20 +1749,20 @@ }, { "cell_type": "code", + "execution_count": 65, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.688400300Z", "start_time": "2026-02-25T17:35:07.677541500Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ], - "outputs": [], - "execution_count": 65 + ] }, { "cell_type": "markdown", @@ -1777,17 +1773,17 @@ }, { "cell_type": "code", + "execution_count": 67, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.718982700Z", "start_time": "2026-02-25T17:35:07.711201900Z" } }, + "outputs": [], "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ], - "outputs": [], - "execution_count": 67 + ] }, { "cell_type": "markdown", @@ -1801,15 +1797,17 @@ }, { "cell_type": "code", + "execution_count": 68, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.837157700Z", "start_time": "2026-02-25T17:35:07.721454600Z" } }, - "source": "results = solver.solve(m, tee=False)", "outputs": [], - "execution_count": 68 + "source": [ + "results = solver.solve(m, tee=False)" + ] }, { "cell_type": "markdown", @@ -1822,33 +1820,19 @@ }, { "cell_type": "code", + "execution_count": 70, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.883912Z", "start_time": "2026-02-25T17:35:07.847804400Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 312674.2367538264\n", + "operating cost = $ 312674.23682387645\n", "\n", "Product flow rate and purity in F102\n", "\n", @@ -1866,29 +1850,19 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", + " flow_mol_phase Liq mole / second 0.28812 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.75463 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.24537 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.032748 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0032478 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.21614 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.74786 4.0825e-08 4.0825e-08 \n", + " temperature kelvin 301.88 362.93 362.93 \n", + " pressure pascal 3.5000e+05 1.0500e+05 1.0500e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.818829588839798\n", + "benzene purity = 0.8188295887582271\n", "\n", "Overhead loss in F101\n", "\n", @@ -1906,31 +1880,35 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", + " flow_mol_phase Liq mole / second 2.6866e-12 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second 1.9480 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.57381 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.42619 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.13952 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.039059 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18417 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.63725 0.74786 0.74786 \n", + " temperature kelvin 600.00 301.88 301.88 \n", + " pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 \n", "====================================================================================\n" ] } ], - "execution_count": 70 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ] }, { "cell_type": "markdown", @@ -1941,27 +1919,13 @@ }, { "cell_type": "code", + "execution_count": 72, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.924695400Z", "start_time": "2026-02-25T17:35:07.893574600Z" } }, - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ], "outputs": [ { "name": "stdout", @@ -1981,7 +1945,21 @@ ] } ], - "execution_count": 72 + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ] } ], "metadata": { @@ -2001,7 +1979,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.12.0" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb index b0956f77..ceb199b6 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb @@ -2,16 +2,18 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "metadata": { - "tags": [ - "header", - "hide-cell" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:01.286374300Z", "start_time": "2026-02-25T17:35:01.274737700Z" - } + }, + "tags": [ + "header", + "hide-cell" + ] }, + "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -25,9 +27,7 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -119,12 +119,14 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:01.830457200Z", "start_time": "2026-02-25T17:35:01.290402400Z" } }, + "outputs": [], "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -136,9 +138,7 @@ " value,\n", ")\n", "from pyomo.network import Arc" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -157,24 +157,28 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.665835Z", "start_time": "2026-02-25T17:35:01.832975100Z" } }, - "source": "from idaes.core import FlowsheetBlock", "outputs": [], - "execution_count": 3 + "source": [ + "from idaes.core import FlowsheetBlock" + ] }, { "cell_type": "code", + "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.734656600Z", "start_time": "2026-02-25T17:35:03.667871Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -185,9 +189,7 @@ " Feed,\n", " Product,\n", ")" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -201,38 +203,38 @@ }, { "cell_type": "code", + "execution_count": 5, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.744136400Z", "start_time": "2026-02-25T17:35:03.736701700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ], - "outputs": [], - "execution_count": 5 + ] }, { "cell_type": "code", + "execution_count": 6, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.752580Z", "start_time": "2026-02-25T17:35:03.745137800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -243,21 +245,21 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.761528300Z", "start_time": "2026-02-25T17:35:03.753588300Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", "from idaes.core.solvers import get_solver" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -278,13 +280,15 @@ ] }, { + "cell_type": "code", + "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.838559500Z", "start_time": "2026-02-25T17:35:03.761528300Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "from idaes.models.properties.modular_properties.base.generic_property import (\n", " GenericParameterBlock,\n", @@ -294,9 +298,7 @@ ")\n", "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -309,18 +311,18 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.849781Z", "start_time": "2026-02-25T17:35:03.841636100Z" } }, + "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "markdown", @@ -331,20 +333,20 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.879447Z", "start_time": "2026-02-25T17:35:03.851130600Z" } }, + "outputs": [], "source": [ "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", "m.fs.reaction_params = GenericReactionParameterBlock(\n", " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -357,12 +359,14 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.925685100Z", "start_time": "2026-02-25T17:35:03.881771100Z" } }, + "outputs": [], "source": [ "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", @@ -377,9 +381,7 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ], - "outputs": [], - "execution_count": 11 + ] }, { "cell_type": "markdown", @@ -404,32 +406,34 @@ }, { "cell_type": "code", + "execution_count": 12, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.935108600Z", "start_time": "2026-02-25T17:35:03.927715700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ], - "outputs": [], - "execution_count": 12 + ] }, { "cell_type": "code", + "execution_count": 13, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.956022500Z", "start_time": "2026-02-25T17:35:03.935614400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -439,9 +443,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ], - "outputs": [], - "execution_count": 13 + ] }, { "cell_type": "markdown", @@ -457,21 +459,21 @@ }, { "cell_type": "code", + "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.979104400Z", "start_time": "2026-02-25T17:35:03.958076200Z" } }, + "outputs": [], "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "markdown", @@ -482,12 +484,14 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.031371300Z", "start_time": "2026-02-25T17:35:03.981638100Z" } }, + "outputs": [], "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -507,9 +511,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 15 + ] }, { "cell_type": "markdown", @@ -520,19 +522,19 @@ }, { "cell_type": "code", + "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.049278900Z", "start_time": "2026-02-25T17:35:04.033910400Z" } }, + "outputs": [], "source": [ "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ], - "outputs": [], - "execution_count": 16 + ] }, { "cell_type": "markdown", @@ -552,19 +554,19 @@ }, { "cell_type": "code", + "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.059097Z", "start_time": "2026-02-25T17:35:04.051649500Z" } }, + "outputs": [], "source": [ "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ], - "outputs": [], - "execution_count": 17 + ] }, { "cell_type": "markdown", @@ -582,38 +584,38 @@ }, { "cell_type": "code", + "execution_count": 18, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.067198800Z", "start_time": "2026-02-25T17:35:04.059097Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ], - "outputs": [], - "execution_count": 18 + ] }, { "cell_type": "code", + "execution_count": 19, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.074873700Z", "start_time": "2026-02-25T17:35:04.067198800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ], - "outputs": [], - "execution_count": 19 + ] }, { "cell_type": "markdown", @@ -624,21 +626,21 @@ }, { "cell_type": "code", + "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.082717500Z", "start_time": "2026-02-25T17:35:04.075379Z" } }, + "outputs": [], "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ], - "outputs": [], - "execution_count": 20 + ] }, { "cell_type": "markdown", @@ -649,19 +651,19 @@ }, { "cell_type": "code", + "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.091461Z", "start_time": "2026-02-25T17:35:04.083716700Z" } }, + "outputs": [], "source": [ "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ], - "outputs": [], - "execution_count": 21 + ] }, { "cell_type": "markdown", @@ -672,17 +674,17 @@ }, { "cell_type": "code", + "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.116142500Z", "start_time": "2026-02-25T17:35:04.092591700Z" } }, + "outputs": [], "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ], - "outputs": [], - "execution_count": 22 + ] }, { "cell_type": "markdown", @@ -704,12 +706,14 @@ }, { "cell_type": "code", + "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.126991900Z", "start_time": "2026-02-25T17:35:04.118294Z" } }, + "outputs": [], "source": [ "m.fs.purity = Expression(\n", " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -722,9 +726,7 @@ " ]\n", " )\n", ")" - ], - "outputs": [], - "execution_count": 23 + ] }, { "cell_type": "markdown", @@ -735,19 +737,19 @@ }, { "cell_type": "code", + "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.134981600Z", "start_time": "2026-02-25T17:35:04.126991900Z" } }, + "outputs": [], "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ], - "outputs": [], - "execution_count": 24 + ] }, { "cell_type": "markdown", @@ -764,19 +766,19 @@ }, { "cell_type": "code", + "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.142918500Z", "start_time": "2026-02-25T17:35:04.134981600Z" } }, + "outputs": [], "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ], - "outputs": [], - "execution_count": 25 + ] }, { "cell_type": "markdown", @@ -787,19 +789,19 @@ }, { "cell_type": "code", + "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.151633300Z", "start_time": "2026-02-25T17:35:04.143918400Z" } }, + "outputs": [], "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ], - "outputs": [], - "execution_count": 26 + ] }, { "cell_type": "markdown", @@ -813,15 +815,13 @@ }, { "cell_type": "code", + "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.183600800Z", "start_time": "2026-02-25T17:35:04.152655800Z" } }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -831,7 +831,9 @@ ] } ], - "execution_count": 27 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "markdown", @@ -845,19 +847,19 @@ }, { "cell_type": "code", + "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.227743300Z", "start_time": "2026-02-25T17:35:04.218810900Z" } }, + "outputs": [], "source": [ "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", "\n", "tear_guesses = fix_inlet_states(m)" - ], - "outputs": [], - "execution_count": 29 + ] }, { "cell_type": "markdown", @@ -870,17 +872,17 @@ }, { "cell_type": "code", + "execution_count": 30, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.235882200Z", "start_time": "2026-02-25T17:35:04.227743300Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ], - "outputs": [], - "execution_count": 30 + ] }, { "cell_type": "markdown", @@ -891,12 +893,14 @@ }, { "cell_type": "code", + "execution_count": 31, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.257770300Z", "start_time": "2026-02-25T17:35:04.236888500Z" } }, + "outputs": [], "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", @@ -913,9 +917,7 @@ "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ], - "outputs": [], - "execution_count": 31 + ] }, { "cell_type": "markdown", @@ -926,18 +928,18 @@ }, { "cell_type": "code", + "execution_count": 32, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.268846Z", "start_time": "2026-02-25T17:35:04.260299600Z" } }, + "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ], - "outputs": [], - "execution_count": 32 + ] }, { "cell_type": "markdown", @@ -961,38 +963,38 @@ }, { "cell_type": "code", + "execution_count": 33, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.278171500Z", "start_time": "2026-02-25T17:35:04.269857200Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ], - "outputs": [], - "execution_count": 33 + ] }, { "cell_type": "code", + "execution_count": 34, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.288481300Z", "start_time": "2026-02-25T17:35:04.279196300Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ], - "outputs": [], - "execution_count": 34 + ] }, { "cell_type": "markdown", @@ -1003,18 +1005,18 @@ }, { "cell_type": "code", + "execution_count": 35, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.302496300Z", "start_time": "2026-02-25T17:35:04.289482700Z" } }, + "outputs": [], "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ], - "outputs": [], - "execution_count": 35 + ] }, { "cell_type": "markdown", @@ -1034,35 +1036,33 @@ }, { "cell_type": "code", + "execution_count": 36, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.312730200Z", "start_time": "2026-02-25T17:35:04.305395100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ], - "outputs": [], - "execution_count": 36 + ] }, { "cell_type": "code", + "execution_count": 37, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.340811100Z", "start_time": "2026-02-25T17:35:04.313761800Z" - } + }, + "tags": [ + "solution" + ] }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -1072,7 +1072,9 @@ ] } ], - "execution_count": 37 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "markdown", @@ -1096,25 +1098,28 @@ ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "First, we will highlight some helpful functions that are used in the initialization process." + "metadata": {}, + "source": [ + "First, we will highlight some helpful functions that are used in the initialization process." + ] }, { + "cell_type": "code", + "execution_count": 39, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.386344500Z", "start_time": "2026-02-25T17:35:04.376804600Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def initialize_unit(unit):\n", " from idaes.core.util.exceptions import InitializationError\n", " import idaes.logger as idaeslog\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", @@ -1126,9 +1131,7 @@ " except InitializationError:\n", " solver = get_solver(solver_options=optarg)\n", " solver.solve(unit)" - ], - "outputs": [], - "execution_count": 39 + ] }, { "cell_type": "markdown", @@ -1145,13 +1148,15 @@ ] }, { + "cell_type": "code", + "execution_count": 40, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.394802500Z", "start_time": "2026-02-25T17:35:04.386344500Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def automatic_propagation(m, tear_guesses):\n", "\n", @@ -1176,9 +1181,7 @@ " print(o[0].name)\n", "\n", " seq.run(m, initialize_unit)" - ], - "outputs": [], - "execution_count": 40 + ] }, { "cell_type": "markdown", @@ -1190,16 +1193,18 @@ ] }, { + "cell_type": "code", + "execution_count": 41, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.404491500Z", "start_time": "2026-02-25T17:35:04.396317500Z" } }, - "cell_type": "code", - "source": "# automatic_propagation(m, tear_guesses)", "outputs": [], - "execution_count": 41 + "source": [ + "# automatic_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1213,12 +1218,14 @@ }, { "cell_type": "code", + "execution_count": 42, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.417815100Z", "start_time": "2026-02-25T17:35:04.404995800Z" } }, + "outputs": [], "source": [ "def manual_propagation(m, tear_guesses):\n", " from idaes.core.util.initialization import propagate_state\n", @@ -1234,7 +1241,6 @@ " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " # \"tol\": 1e-10,\n", @@ -1275,7 +1281,6 @@ " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " \"tol\": 1e-8,\n", @@ -1291,9 +1296,7 @@ " print(\n", " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", " )" - ], - "outputs": [], - "execution_count": 42 + ] }, { "cell_type": "markdown", @@ -1308,13 +1311,13 @@ }, { "cell_type": "code", + "execution_count": 43, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.145125500Z", "start_time": "2026-02-25T17:35:04.419335500Z" } }, - "source": "manual_propagation(m, tear_guesses)", "outputs": [ { "name": "stdout", @@ -1327,7 +1330,9 @@ ] } ], - "execution_count": 43 + "source": [ + "manual_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1347,22 +1352,21 @@ }, { "cell_type": "code", + "execution_count": 44, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.161129400Z", "start_time": "2026-02-25T17:35:07.146644300Z" } }, + "outputs": [], "source": [ "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", "}" - ], - "outputs": [], - "execution_count": 44 + ] }, { "cell_type": "markdown", @@ -1385,43 +1389,43 @@ }, { "cell_type": "code", + "execution_count": 45, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.170980400Z", "start_time": "2026-02-25T17:35:07.163178100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "\n", "# Solve the model" - ], - "outputs": [], - "execution_count": 45 + ] }, { "cell_type": "code", + "execution_count": 46, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.272798500Z", "start_time": "2026-02-25T17:35:07.170980400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=False)" - ], - "outputs": [], - "execution_count": 46 + ] }, { "cell_type": "markdown", @@ -1441,20 +1445,20 @@ }, { "cell_type": "code", + "execution_count": 48, "metadata": { - "tags": [ - "noauto" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.302463Z", "start_time": "2026-02-25T17:35:07.282944100Z" - } + }, + "tags": [ + "noauto" + ] }, + "outputs": [], "source": [ "# m.fs.visualize(\"HDA-Flowsheet\")" - ], - "outputs": [], - "execution_count": 48 + ] }, { "cell_type": "markdown", @@ -1465,15 +1469,13 @@ }, { "cell_type": "code", + "execution_count": 49, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.337983600Z", "start_time": "2026-02-25T17:35:07.303479400Z" } }, - "source": [ - "m.fs.report()" - ], "outputs": [ { "name": "stdout", @@ -1485,21 +1487,23 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 1.6736e-09 1.8681e-09 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7852e-07\n", " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.8212e-08 1.8212e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.8268e-08 4.8268e-08 0.72074\n", " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", "====================================================================================\n" ] } ], - "execution_count": 49 + "source": [ + "m.fs.report()" + ] }, { "cell_type": "markdown", @@ -1510,25 +1514,25 @@ }, { "cell_type": "code", + "execution_count": 50, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.355013500Z", "start_time": "2026-02-25T17:35:07.346055600Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 419008.28211932775\n" + "operating cost = $ 419008.28599155403\n" ] } ], - "execution_count": 50 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ] }, { "cell_type": "markdown", @@ -1539,18 +1543,13 @@ }, { "cell_type": "code", + "execution_count": 52, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.469810Z", "start_time": "2026-02-25T17:35:07.452663800Z" } }, - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ], "outputs": [ { "name": "stdout", @@ -1571,33 +1570,28 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", + " flow_mol_phase Liq mole / second 0.26712 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.76595 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.23405 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.084499 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0088437 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18592 1.8212e-08 1.8212e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.72074 4.8268e-08 4.8268e-08 \n", + " temperature kelvin 325.00 375.00 375.00 \n", + " pressure pascal 3.5000e+05 1.5000e+05 1.5000e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.8242963521555953\n" + "benzene purity = 0.8242963399526197\n" ] } ], - "execution_count": 52 + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ] }, { "cell_type": "markdown", @@ -1608,28 +1602,20 @@ }, { "cell_type": "code", + "execution_count": 54, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.503351300Z", "start_time": "2026-02-25T17:35:07.487979400Z" } }, - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Liq mole / second 1.8681e-09 1.0000e-08 \n", "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", @@ -1642,7 +1628,15 @@ ] } ], - "execution_count": 54 + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ] }, { "cell_type": "markdown", @@ -1675,17 +1669,17 @@ }, { "cell_type": "code", + "execution_count": 55, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.523495700Z", "start_time": "2026-02-25T17:35:07.513232100Z" } }, + "outputs": [], "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ], - "outputs": [], - "execution_count": 55 + ] }, { "cell_type": "markdown", @@ -1698,21 +1692,21 @@ }, { "cell_type": "code", + "execution_count": 56, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.538051100Z", "start_time": "2026-02-25T17:35:07.528058900Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.R101.outlet.temperature.fix(600)\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ], - "outputs": [], - "execution_count": 56 + ] }, { "cell_type": "markdown", @@ -1733,38 +1727,38 @@ }, { "cell_type": "code", + "execution_count": 57, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.568196100Z", "start_time": "2026-02-25T17:35:07.545899Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ], - "outputs": [], - "execution_count": 57 + ] }, { "cell_type": "code", + "execution_count": 58, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.578318700Z", "start_time": "2026-02-25T17:35:07.571295800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ], - "outputs": [], - "execution_count": 58 + ] }, { "cell_type": "markdown", @@ -1782,18 +1776,18 @@ }, { "cell_type": "code", + "execution_count": 60, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.627054600Z", "start_time": "2026-02-25T17:35:07.619525700Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ], - "outputs": [], - "execution_count": 60 + ] }, { "cell_type": "markdown", @@ -1813,37 +1807,39 @@ }, { "cell_type": "code", + "execution_count": 61, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.638684200Z", "start_time": "2026-02-25T17:35:07.630104900Z" - } + }, + "tags": [ + "exercise" + ] }, - "source": "# Todo: Set the bounds for flash 101 outlet temperature", "outputs": [], - "execution_count": 61 + "source": [ + "# Todo: Set the bounds for flash 101 outlet temperature" + ] }, { "cell_type": "code", + "execution_count": 62, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.652892600Z", "start_time": "2026-02-25T17:35:07.643756900Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" - ], - "outputs": [], - "execution_count": 62 + ] }, { "cell_type": "markdown", @@ -1854,20 +1850,20 @@ }, { "cell_type": "code", + "execution_count": 63, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.662831700Z", "start_time": "2026-02-25T17:35:07.654919400Z" } }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ], - "outputs": [], - "execution_count": 63 + ] }, { "cell_type": "markdown", @@ -1878,12 +1874,14 @@ }, { "cell_type": "code", + "execution_count": 64, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.673507300Z", "start_time": "2026-02-25T17:35:07.666381200Z" } }, + "outputs": [], "source": [ "m.fs.overhead_loss = Constraint(\n", " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -1892,9 +1890,7 @@ " <= 0.20\n", " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ], - "outputs": [], - "execution_count": 64 + ] }, { "cell_type": "markdown", @@ -1914,32 +1910,34 @@ }, { "cell_type": "code", + "execution_count": 65, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.688400300Z", "start_time": "2026-02-25T17:35:07.677541500Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ], - "outputs": [], - "execution_count": 65 + ] }, { "cell_type": "code", + "execution_count": 66, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.707964Z", "start_time": "2026-02-25T17:35:07.699126100Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", @@ -1948,9 +1946,7 @@ " ]\n", " >= 0.15\n", ")" - ], - "outputs": [], - "execution_count": 66 + ] }, { "cell_type": "markdown", @@ -1961,17 +1957,17 @@ }, { "cell_type": "code", + "execution_count": 67, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.718982700Z", "start_time": "2026-02-25T17:35:07.711201900Z" } }, + "outputs": [], "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ], - "outputs": [], - "execution_count": 67 + ] }, { "cell_type": "markdown", @@ -1985,15 +1981,17 @@ }, { "cell_type": "code", + "execution_count": 68, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.837157700Z", "start_time": "2026-02-25T17:35:07.721454600Z" } }, - "source": "results = solver.solve(m, tee=False)", "outputs": [], - "execution_count": 68 + "source": [ + "results = solver.solve(m, tee=False)" + ] }, { "cell_type": "markdown", @@ -2006,33 +2004,19 @@ }, { "cell_type": "code", + "execution_count": 70, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.883912Z", "start_time": "2026-02-25T17:35:07.847804400Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 312674.2367538264\n", + "operating cost = $ 312674.23682387645\n", "\n", "Product flow rate and purity in F102\n", "\n", @@ -2050,29 +2034,19 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", + " flow_mol_phase Liq mole / second 0.28812 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.75463 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.24537 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.032748 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0032478 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.21614 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.74786 4.0825e-08 4.0825e-08 \n", + " temperature kelvin 301.88 362.93 362.93 \n", + " pressure pascal 3.5000e+05 1.0500e+05 1.0500e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.818829588839798\n", + "benzene purity = 0.8188295887582271\n", "\n", "Overhead loss in F101\n", "\n", @@ -2090,31 +2064,35 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", + " flow_mol_phase Liq mole / second 2.6866e-12 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second 1.9480 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.57381 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.42619 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.13952 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.039059 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18417 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.63725 0.74786 0.74786 \n", + " temperature kelvin 600.00 301.88 301.88 \n", + " pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 \n", "====================================================================================\n" ] } ], - "execution_count": 70 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ] }, { "cell_type": "markdown", @@ -2125,27 +2103,13 @@ }, { "cell_type": "code", + "execution_count": 72, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.924695400Z", "start_time": "2026-02-25T17:35:07.893574600Z" } }, - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ], "outputs": [ { "name": "stdout", @@ -2165,7 +2129,21 @@ ] } ], - "execution_count": 72 + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ] } ], "metadata": { @@ -2185,7 +2163,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.12.0" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb index f5f0243b..f4a9aefa 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb @@ -2,16 +2,18 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "metadata": { - "tags": [ - "header", - "hide-cell" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:01.286374300Z", "start_time": "2026-02-25T17:35:01.274737700Z" - } + }, + "tags": [ + "header", + "hide-cell" + ] }, + "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -25,9 +27,7 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -119,12 +119,14 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:01.830457200Z", "start_time": "2026-02-25T17:35:01.290402400Z" } }, + "outputs": [], "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -136,9 +138,7 @@ " value,\n", ")\n", "from pyomo.network import Arc" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -157,24 +157,28 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.665835Z", "start_time": "2026-02-25T17:35:01.832975100Z" } }, - "source": "from idaes.core import FlowsheetBlock", "outputs": [], - "execution_count": 3 + "source": [ + "from idaes.core import FlowsheetBlock" + ] }, { "cell_type": "code", + "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.734656600Z", "start_time": "2026-02-25T17:35:03.667871Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -185,9 +189,7 @@ " Feed,\n", " Product,\n", ")" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -201,21 +203,21 @@ }, { "cell_type": "code", + "execution_count": 6, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.752580Z", "start_time": "2026-02-25T17:35:03.745137800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -226,21 +228,21 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.761528300Z", "start_time": "2026-02-25T17:35:03.753588300Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", "from idaes.core.solvers import get_solver" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -261,13 +263,15 @@ ] }, { + "cell_type": "code", + "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.838559500Z", "start_time": "2026-02-25T17:35:03.761528300Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "from idaes.models.properties.modular_properties.base.generic_property import (\n", " GenericParameterBlock,\n", @@ -277,9 +281,7 @@ ")\n", "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -292,18 +294,18 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.849781Z", "start_time": "2026-02-25T17:35:03.841636100Z" } }, + "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "markdown", @@ -314,20 +316,20 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.879447Z", "start_time": "2026-02-25T17:35:03.851130600Z" } }, + "outputs": [], "source": [ "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", "m.fs.reaction_params = GenericReactionParameterBlock(\n", " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -340,12 +342,14 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.925685100Z", "start_time": "2026-02-25T17:35:03.881771100Z" } }, + "outputs": [], "source": [ "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", @@ -360,21 +364,21 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ], - "outputs": [], - "execution_count": 11 + ] }, { "cell_type": "code", + "execution_count": 13, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.956022500Z", "start_time": "2026-02-25T17:35:03.935614400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -384,9 +388,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ], - "outputs": [], - "execution_count": 13 + ] }, { "cell_type": "markdown", @@ -402,21 +404,21 @@ }, { "cell_type": "code", + "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.979104400Z", "start_time": "2026-02-25T17:35:03.958076200Z" } }, + "outputs": [], "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "markdown", @@ -427,12 +429,14 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.031371300Z", "start_time": "2026-02-25T17:35:03.981638100Z" } }, + "outputs": [], "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -452,9 +456,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 15 + ] }, { "cell_type": "markdown", @@ -465,19 +467,19 @@ }, { "cell_type": "code", + "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.049278900Z", "start_time": "2026-02-25T17:35:04.033910400Z" } }, + "outputs": [], "source": [ "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ], - "outputs": [], - "execution_count": 16 + ] }, { "cell_type": "markdown", @@ -497,37 +499,37 @@ }, { "cell_type": "code", + "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.059097Z", "start_time": "2026-02-25T17:35:04.051649500Z" } }, + "outputs": [], "source": [ "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ], - "outputs": [], - "execution_count": 17 + ] }, { "cell_type": "code", + "execution_count": 19, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.074873700Z", "start_time": "2026-02-25T17:35:04.067198800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ], - "outputs": [], - "execution_count": 19 + ] }, { "cell_type": "markdown", @@ -538,21 +540,21 @@ }, { "cell_type": "code", + "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.082717500Z", "start_time": "2026-02-25T17:35:04.075379Z" } }, + "outputs": [], "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ], - "outputs": [], - "execution_count": 20 + ] }, { "cell_type": "markdown", @@ -563,19 +565,19 @@ }, { "cell_type": "code", + "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.091461Z", "start_time": "2026-02-25T17:35:04.083716700Z" } }, + "outputs": [], "source": [ "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ], - "outputs": [], - "execution_count": 21 + ] }, { "cell_type": "markdown", @@ -586,17 +588,17 @@ }, { "cell_type": "code", + "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.116142500Z", "start_time": "2026-02-25T17:35:04.092591700Z" } }, + "outputs": [], "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ], - "outputs": [], - "execution_count": 22 + ] }, { "cell_type": "markdown", @@ -618,12 +620,14 @@ }, { "cell_type": "code", + "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.126991900Z", "start_time": "2026-02-25T17:35:04.118294Z" } }, + "outputs": [], "source": [ "m.fs.purity = Expression(\n", " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -636,9 +640,7 @@ " ]\n", " )\n", ")" - ], - "outputs": [], - "execution_count": 23 + ] }, { "cell_type": "markdown", @@ -649,19 +651,19 @@ }, { "cell_type": "code", + "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.134981600Z", "start_time": "2026-02-25T17:35:04.126991900Z" } }, + "outputs": [], "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ], - "outputs": [], - "execution_count": 24 + ] }, { "cell_type": "markdown", @@ -678,19 +680,19 @@ }, { "cell_type": "code", + "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.142918500Z", "start_time": "2026-02-25T17:35:04.134981600Z" } }, + "outputs": [], "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ], - "outputs": [], - "execution_count": 25 + ] }, { "cell_type": "markdown", @@ -701,19 +703,19 @@ }, { "cell_type": "code", + "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.151633300Z", "start_time": "2026-02-25T17:35:04.143918400Z" } }, + "outputs": [], "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ], - "outputs": [], - "execution_count": 26 + ] }, { "cell_type": "markdown", @@ -727,15 +729,13 @@ }, { "cell_type": "code", + "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.183600800Z", "start_time": "2026-02-25T17:35:04.152655800Z" } }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -745,25 +745,27 @@ ] } ], - "execution_count": 27 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "code", + "execution_count": 28, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.216388800Z", "start_time": "2026-02-25T17:35:04.187853900Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 29" - ], - "outputs": [], - "execution_count": 28 + ] }, { "cell_type": "markdown", @@ -777,19 +779,19 @@ }, { "cell_type": "code", + "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.227743300Z", "start_time": "2026-02-25T17:35:04.218810900Z" } }, + "outputs": [], "source": [ "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", "\n", "tear_guesses = fix_inlet_states(m)" - ], - "outputs": [], - "execution_count": 29 + ] }, { "cell_type": "markdown", @@ -802,17 +804,17 @@ }, { "cell_type": "code", + "execution_count": 30, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.235882200Z", "start_time": "2026-02-25T17:35:04.227743300Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ], - "outputs": [], - "execution_count": 30 + ] }, { "cell_type": "markdown", @@ -823,12 +825,14 @@ }, { "cell_type": "code", + "execution_count": 31, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.257770300Z", "start_time": "2026-02-25T17:35:04.236888500Z" } }, + "outputs": [], "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", @@ -845,9 +849,7 @@ "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ], - "outputs": [], - "execution_count": 31 + ] }, { "cell_type": "markdown", @@ -858,36 +860,36 @@ }, { "cell_type": "code", + "execution_count": 32, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.268846Z", "start_time": "2026-02-25T17:35:04.260299600Z" } }, + "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ], - "outputs": [], - "execution_count": 32 + ] }, { "cell_type": "code", + "execution_count": 34, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.288481300Z", "start_time": "2026-02-25T17:35:04.279196300Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ], - "outputs": [], - "execution_count": 34 + ] }, { "cell_type": "markdown", @@ -898,33 +900,31 @@ }, { "cell_type": "code", + "execution_count": 35, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.302496300Z", "start_time": "2026-02-25T17:35:04.289482700Z" } }, + "outputs": [], "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ], - "outputs": [], - "execution_count": 35 + ] }, { "cell_type": "code", + "execution_count": 37, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.340811100Z", "start_time": "2026-02-25T17:35:04.313761800Z" - } + }, + "tags": [ + "solution" + ] }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -934,25 +934,27 @@ ] } ], - "execution_count": 37 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "code", + "execution_count": 38, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.374728400Z", "start_time": "2026-02-25T17:35:04.345879200Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 0" - ], - "outputs": [], - "execution_count": 38 + ] }, { "cell_type": "markdown", @@ -976,25 +978,28 @@ ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "First, we will highlight some helpful functions that are used in the initialization process." + "metadata": {}, + "source": [ + "First, we will highlight some helpful functions that are used in the initialization process." + ] }, { + "cell_type": "code", + "execution_count": 39, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.386344500Z", "start_time": "2026-02-25T17:35:04.376804600Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def initialize_unit(unit):\n", " from idaes.core.util.exceptions import InitializationError\n", " import idaes.logger as idaeslog\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", @@ -1006,9 +1011,7 @@ " except InitializationError:\n", " solver = get_solver(solver_options=optarg)\n", " solver.solve(unit)" - ], - "outputs": [], - "execution_count": 39 + ] }, { "cell_type": "markdown", @@ -1025,13 +1028,15 @@ ] }, { + "cell_type": "code", + "execution_count": 40, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.394802500Z", "start_time": "2026-02-25T17:35:04.386344500Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def automatic_propagation(m, tear_guesses):\n", "\n", @@ -1056,9 +1061,7 @@ " print(o[0].name)\n", "\n", " seq.run(m, initialize_unit)" - ], - "outputs": [], - "execution_count": 40 + ] }, { "cell_type": "markdown", @@ -1070,16 +1073,18 @@ ] }, { + "cell_type": "code", + "execution_count": 41, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.404491500Z", "start_time": "2026-02-25T17:35:04.396317500Z" } }, - "cell_type": "code", - "source": "# automatic_propagation(m, tear_guesses)", "outputs": [], - "execution_count": 41 + "source": [ + "# automatic_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1093,12 +1098,14 @@ }, { "cell_type": "code", + "execution_count": 42, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.417815100Z", "start_time": "2026-02-25T17:35:04.404995800Z" } }, + "outputs": [], "source": [ "def manual_propagation(m, tear_guesses):\n", " from idaes.core.util.initialization import propagate_state\n", @@ -1114,7 +1121,6 @@ " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " # \"tol\": 1e-10,\n", @@ -1155,7 +1161,6 @@ " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " \"tol\": 1e-8,\n", @@ -1171,9 +1176,7 @@ " print(\n", " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", " )" - ], - "outputs": [], - "execution_count": 42 + ] }, { "cell_type": "markdown", @@ -1188,13 +1191,13 @@ }, { "cell_type": "code", + "execution_count": 43, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.145125500Z", "start_time": "2026-02-25T17:35:04.419335500Z" } }, - "source": "manual_propagation(m, tear_guesses)", "outputs": [ { "name": "stdout", @@ -1207,7 +1210,9 @@ ] } ], - "execution_count": 43 + "source": [ + "manual_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1227,63 +1232,62 @@ }, { "cell_type": "code", + "execution_count": 44, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.161129400Z", "start_time": "2026-02-25T17:35:07.146644300Z" } }, + "outputs": [], "source": [ "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", "}" - ], - "outputs": [], - "execution_count": 44 + ] }, { "cell_type": "code", + "execution_count": 46, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.272798500Z", "start_time": "2026-02-25T17:35:07.170980400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=False)" - ], - "outputs": [], - "execution_count": 46 + ] }, { "cell_type": "code", + "execution_count": 47, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.281939700Z", "start_time": "2026-02-25T17:35:07.274820400Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 47 + ] }, { "cell_type": "markdown", @@ -1310,15 +1314,13 @@ }, { "cell_type": "code", + "execution_count": 49, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.337983600Z", "start_time": "2026-02-25T17:35:07.303479400Z" } }, - "source": [ - "m.fs.report()" - ], "outputs": [ { "name": "stdout", @@ -1330,21 +1332,23 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 1.6736e-09 1.8681e-09 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7852e-07\n", " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.8212e-08 1.8212e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.8268e-08 4.8268e-08 0.72074\n", " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", "====================================================================================\n" ] } ], - "execution_count": 49 + "source": [ + "m.fs.report()" + ] }, { "cell_type": "markdown", @@ -1355,44 +1359,44 @@ }, { "cell_type": "code", + "execution_count": 50, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.355013500Z", "start_time": "2026-02-25T17:35:07.346055600Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 419008.28211932775\n" + "operating cost = $ 419008.28599155403\n" ] } ], - "execution_count": 50 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ] }, { "cell_type": "code", + "execution_count": 51, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.449306200Z", "start_time": "2026-02-25T17:35:07.358159700Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "import pytest\n", "\n", - "assert value(m.fs.operating_cost) == pytest.approx(419008.28189, abs=1e-3)" - ], - "outputs": [], - "execution_count": 51 + "assert value(m.fs.operating_cost) == pytest.approx(419008.28189, rel=1e-4)" + ] }, { "cell_type": "markdown", @@ -1403,18 +1407,13 @@ }, { "cell_type": "code", + "execution_count": 52, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.469810Z", "start_time": "2026-02-25T17:35:07.452663800Z" } }, - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ], "outputs": [ { "name": "stdout", @@ -1435,52 +1434,47 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", + " flow_mol_phase Liq mole / second 0.26712 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.76595 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.23405 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.084499 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0088437 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18592 1.8212e-08 1.8212e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.72074 4.8268e-08 4.8268e-08 \n", + " temperature kelvin 325.00 375.00 375.00 \n", + " pressure pascal 3.5000e+05 1.5000e+05 1.5000e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.8242963521555953\n" + "benzene purity = 0.8242963399526197\n" ] } ], - "execution_count": 52 + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ] }, { "cell_type": "code", + "execution_count": 53, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.486974600Z", "start_time": "2026-02-25T17:35:07.477988200Z" - } + }, + "tags": [ + "testing" + ] }, - "source": [ - "assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3)\n", - "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3)" - ], "outputs": [], - "execution_count": 53 + "source": [ + "assert value(m.fs.purity) == pytest.approx(0.82429, rel=1e-4)\n", + "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.67441, rel=1e-4)\n", + "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, rel=1e-4)" + ] }, { "cell_type": "markdown", @@ -1491,28 +1485,20 @@ }, { "cell_type": "code", + "execution_count": 54, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.503351300Z", "start_time": "2026-02-25T17:35:07.487979400Z" } }, - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Liq mole / second 1.8681e-09 1.0000e-08 \n", "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", @@ -1525,7 +1511,15 @@ ] } ], - "execution_count": 54 + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ] }, { "cell_type": "markdown", @@ -1558,17 +1552,17 @@ }, { "cell_type": "code", + "execution_count": 55, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.523495700Z", "start_time": "2026-02-25T17:35:07.513232100Z" } }, + "outputs": [], "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ], - "outputs": [], - "execution_count": 55 + ] }, { "cell_type": "markdown", @@ -1581,54 +1575,56 @@ }, { "cell_type": "code", + "execution_count": 56, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.538051100Z", "start_time": "2026-02-25T17:35:07.528058900Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.R101.outlet.temperature.fix(600)\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ], - "outputs": [], - "execution_count": 56 + ] }, { "cell_type": "code", + "execution_count": 58, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.578318700Z", "start_time": "2026-02-25T17:35:07.571295800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ], - "outputs": [], - "execution_count": 58 + ] }, { "cell_type": "code", + "execution_count": 59, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.616492Z", "start_time": "2026-02-25T17:35:07.581710400Z" - } + }, + "tags": [ + "testing" + ] }, - "source": "assert degrees_of_freedom(m) == 4", "outputs": [], - "execution_count": 59 + "source": [ + "assert degrees_of_freedom(m) == 4" + ] }, { "cell_type": "markdown", @@ -1646,37 +1642,37 @@ }, { "cell_type": "code", + "execution_count": 60, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.627054600Z", "start_time": "2026-02-25T17:35:07.619525700Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ], - "outputs": [], - "execution_count": 60 + ] }, { "cell_type": "code", + "execution_count": 62, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.652892600Z", "start_time": "2026-02-25T17:35:07.643756900Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" - ], - "outputs": [], - "execution_count": 62 + ] }, { "cell_type": "markdown", @@ -1687,20 +1683,20 @@ }, { "cell_type": "code", + "execution_count": 63, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.662831700Z", "start_time": "2026-02-25T17:35:07.654919400Z" } }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ], - "outputs": [], - "execution_count": 63 + ] }, { "cell_type": "markdown", @@ -1711,12 +1707,14 @@ }, { "cell_type": "code", + "execution_count": 64, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.673507300Z", "start_time": "2026-02-25T17:35:07.666381200Z" } }, + "outputs": [], "source": [ "m.fs.overhead_loss = Constraint(\n", " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -1725,21 +1723,21 @@ " <= 0.20\n", " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ], - "outputs": [], - "execution_count": 64 + ] }, { "cell_type": "code", + "execution_count": 66, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.707964Z", "start_time": "2026-02-25T17:35:07.699126100Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", @@ -1748,9 +1746,7 @@ " ]\n", " >= 0.15\n", ")" - ], - "outputs": [], - "execution_count": 66 + ] }, { "cell_type": "markdown", @@ -1761,17 +1757,17 @@ }, { "cell_type": "code", + "execution_count": 67, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.718982700Z", "start_time": "2026-02-25T17:35:07.711201900Z" } }, + "outputs": [], "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ], - "outputs": [], - "execution_count": 67 + ] }, { "cell_type": "markdown", @@ -1785,35 +1781,37 @@ }, { "cell_type": "code", + "execution_count": 68, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.837157700Z", "start_time": "2026-02-25T17:35:07.721454600Z" } }, - "source": "results = solver.solve(m, tee=False)", "outputs": [], - "execution_count": 68 + "source": [ + "results = solver.solve(m, tee=False)" + ] }, { "cell_type": "code", + "execution_count": 69, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.846796Z", "start_time": "2026-02-25T17:35:07.839188400Z" - } + }, + "tags": [ + "testing" + ] }, + "outputs": [], "source": [ "# Check for solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ], - "outputs": [], - "execution_count": 69 + ] }, { "cell_type": "markdown", @@ -1826,33 +1824,19 @@ }, { "cell_type": "code", + "execution_count": 70, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.883912Z", "start_time": "2026-02-25T17:35:07.847804400Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 312674.2367538264\n", + "operating cost = $ 312674.23682387645\n", "\n", "Product flow rate and purity in F102\n", "\n", @@ -1870,29 +1854,19 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", + " flow_mol_phase Liq mole / second 0.28812 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.75463 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.24537 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.032748 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0032478 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.21614 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.74786 4.0825e-08 4.0825e-08 \n", + " temperature kelvin 301.88 362.93 362.93 \n", + " pressure pascal 3.5000e+05 1.0500e+05 1.0500e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.818829588839798\n", + "benzene purity = 0.8188295887582271\n", "\n", "Overhead loss in F101\n", "\n", @@ -1910,49 +1884,53 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", + " flow_mol_phase Liq mole / second 2.6866e-12 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second 1.9480 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.57381 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.42619 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.13952 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.039059 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18417 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.63725 0.74786 0.74786 \n", + " temperature kelvin 600.00 301.88 301.88 \n", + " pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 \n", "====================================================================================\n" ] } ], - "execution_count": 70 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ] }, { "cell_type": "code", + "execution_count": 71, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.893574600Z", "start_time": "2026-02-25T17:35:07.884912500Z" - } + }, + "tags": [ + "testing" + ] }, - "source": [ - "assert value(m.fs.operating_cost) == pytest.approx(312674.236, abs=1e-3)\n", - "assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3)" - ], "outputs": [], - "execution_count": 71 + "source": [ + "assert value(m.fs.operating_cost) == pytest.approx(312674.236, rel=1e-4)\n", + "assert value(m.fs.purity) == pytest.approx(0.818827, rel=1e-4)" + ] }, { "cell_type": "markdown", @@ -1963,27 +1941,13 @@ }, { "cell_type": "code", + "execution_count": 72, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.924695400Z", "start_time": "2026-02-25T17:35:07.893574600Z" } }, - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ], "outputs": [ { "name": "stdout", @@ -2003,28 +1967,42 @@ ] } ], - "execution_count": 72 + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ] }, { "cell_type": "code", + "execution_count": 73, "metadata": { - "tags": [ - "testing" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.935546Z", "start_time": "2026-02-25T17:35:07.925710Z" - } + }, + "tags": [ + "testing" + ] }, - "source": [ - "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3)\n", - "assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, abs=1e-3)\n", - "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, abs=1e-3)\n", - "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2)" - ], "outputs": [], - "execution_count": 73 + "source": [ + "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, rel=1e-4)\n", + "assert value(m.fs.R101.heat_duty[0]) == pytest.approx(-13766.243, rel=1e-4)\n", + "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, rel=1e-4)\n", + "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, rel=1e-4)\n", + "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, rel=1e-4)" + ] } ], "metadata": { @@ -2044,7 +2022,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.12.0" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb index b0956f77..ceb199b6 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb @@ -2,16 +2,18 @@ "cells": [ { "cell_type": "code", + "execution_count": 1, "metadata": { - "tags": [ - "header", - "hide-cell" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:01.286374300Z", "start_time": "2026-02-25T17:35:01.274737700Z" - } + }, + "tags": [ + "header", + "hide-cell" + ] }, + "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -25,9 +27,7 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -119,12 +119,14 @@ }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:01.830457200Z", "start_time": "2026-02-25T17:35:01.290402400Z" } }, + "outputs": [], "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -136,9 +138,7 @@ " value,\n", ")\n", "from pyomo.network import Arc" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -157,24 +157,28 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.665835Z", "start_time": "2026-02-25T17:35:01.832975100Z" } }, - "source": "from idaes.core import FlowsheetBlock", "outputs": [], - "execution_count": 3 + "source": [ + "from idaes.core import FlowsheetBlock" + ] }, { "cell_type": "code", + "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.734656600Z", "start_time": "2026-02-25T17:35:03.667871Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -185,9 +189,7 @@ " Feed,\n", " Product,\n", ")" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -201,38 +203,38 @@ }, { "cell_type": "code", + "execution_count": 5, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.744136400Z", "start_time": "2026-02-25T17:35:03.736701700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ], - "outputs": [], - "execution_count": 5 + ] }, { "cell_type": "code", + "execution_count": 6, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.752580Z", "start_time": "2026-02-25T17:35:03.745137800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -243,21 +245,21 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.761528300Z", "start_time": "2026-02-25T17:35:03.753588300Z" } }, + "outputs": [], "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", "from idaes.core.solvers import get_solver" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -278,13 +280,15 @@ ] }, { + "cell_type": "code", + "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.838559500Z", "start_time": "2026-02-25T17:35:03.761528300Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "from idaes.models.properties.modular_properties.base.generic_property import (\n", " GenericParameterBlock,\n", @@ -294,9 +298,7 @@ ")\n", "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -309,18 +311,18 @@ }, { "cell_type": "code", + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.849781Z", "start_time": "2026-02-25T17:35:03.841636100Z" } }, + "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "markdown", @@ -331,20 +333,20 @@ }, { "cell_type": "code", + "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.879447Z", "start_time": "2026-02-25T17:35:03.851130600Z" } }, + "outputs": [], "source": [ "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", "m.fs.reaction_params = GenericReactionParameterBlock(\n", " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -357,12 +359,14 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.925685100Z", "start_time": "2026-02-25T17:35:03.881771100Z" } }, + "outputs": [], "source": [ "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", @@ -377,9 +381,7 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ], - "outputs": [], - "execution_count": 11 + ] }, { "cell_type": "markdown", @@ -404,32 +406,34 @@ }, { "cell_type": "code", + "execution_count": 12, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.935108600Z", "start_time": "2026-02-25T17:35:03.927715700Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ], - "outputs": [], - "execution_count": 12 + ] }, { "cell_type": "code", + "execution_count": 13, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:03.956022500Z", "start_time": "2026-02-25T17:35:03.935614400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -439,9 +443,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ], - "outputs": [], - "execution_count": 13 + ] }, { "cell_type": "markdown", @@ -457,21 +459,21 @@ }, { "cell_type": "code", + "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:03.979104400Z", "start_time": "2026-02-25T17:35:03.958076200Z" } }, + "outputs": [], "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "markdown", @@ -482,12 +484,14 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.031371300Z", "start_time": "2026-02-25T17:35:03.981638100Z" } }, + "outputs": [], "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -507,9 +511,7 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ], - "outputs": [], - "execution_count": 15 + ] }, { "cell_type": "markdown", @@ -520,19 +522,19 @@ }, { "cell_type": "code", + "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.049278900Z", "start_time": "2026-02-25T17:35:04.033910400Z" } }, + "outputs": [], "source": [ "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", "m.fs.P103 = Product(property_package=m.fs.thermo_params)" - ], - "outputs": [], - "execution_count": 16 + ] }, { "cell_type": "markdown", @@ -552,19 +554,19 @@ }, { "cell_type": "code", + "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.059097Z", "start_time": "2026-02-25T17:35:04.051649500Z" } }, + "outputs": [], "source": [ "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" - ], - "outputs": [], - "execution_count": 17 + ] }, { "cell_type": "markdown", @@ -582,38 +584,38 @@ }, { "cell_type": "code", + "execution_count": 18, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.067198800Z", "start_time": "2026-02-25T17:35:04.059097Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ], - "outputs": [], - "execution_count": 18 + ] }, { "cell_type": "code", + "execution_count": 19, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.074873700Z", "start_time": "2026-02-25T17:35:04.067198800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ], - "outputs": [], - "execution_count": 19 + ] }, { "cell_type": "markdown", @@ -624,21 +626,21 @@ }, { "cell_type": "code", + "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.082717500Z", "start_time": "2026-02-25T17:35:04.075379Z" } }, + "outputs": [], "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" - ], - "outputs": [], - "execution_count": 20 + ] }, { "cell_type": "markdown", @@ -649,19 +651,19 @@ }, { "cell_type": "code", + "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.091461Z", "start_time": "2026-02-25T17:35:04.083716700Z" } }, + "outputs": [], "source": [ "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" - ], - "outputs": [], - "execution_count": 21 + ] }, { "cell_type": "markdown", @@ -672,17 +674,17 @@ }, { "cell_type": "code", + "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.116142500Z", "start_time": "2026-02-25T17:35:04.092591700Z" } }, + "outputs": [], "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ], - "outputs": [], - "execution_count": 22 + ] }, { "cell_type": "markdown", @@ -704,12 +706,14 @@ }, { "cell_type": "code", + "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.126991900Z", "start_time": "2026-02-25T17:35:04.118294Z" } }, + "outputs": [], "source": [ "m.fs.purity = Expression(\n", " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -722,9 +726,7 @@ " ]\n", " )\n", ")" - ], - "outputs": [], - "execution_count": 23 + ] }, { "cell_type": "markdown", @@ -735,19 +737,19 @@ }, { "cell_type": "code", + "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.134981600Z", "start_time": "2026-02-25T17:35:04.126991900Z" } }, + "outputs": [], "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ], - "outputs": [], - "execution_count": 24 + ] }, { "cell_type": "markdown", @@ -764,19 +766,19 @@ }, { "cell_type": "code", + "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.142918500Z", "start_time": "2026-02-25T17:35:04.134981600Z" } }, + "outputs": [], "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ], - "outputs": [], - "execution_count": 25 + ] }, { "cell_type": "markdown", @@ -787,19 +789,19 @@ }, { "cell_type": "code", + "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.151633300Z", "start_time": "2026-02-25T17:35:04.143918400Z" } }, + "outputs": [], "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ], - "outputs": [], - "execution_count": 26 + ] }, { "cell_type": "markdown", @@ -813,15 +815,13 @@ }, { "cell_type": "code", + "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.183600800Z", "start_time": "2026-02-25T17:35:04.152655800Z" } }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -831,7 +831,9 @@ ] } ], - "execution_count": 27 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "markdown", @@ -845,19 +847,19 @@ }, { "cell_type": "code", + "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.227743300Z", "start_time": "2026-02-25T17:35:04.218810900Z" } }, + "outputs": [], "source": [ "from idaes_examples.mod.hda.hda_flowsheet_extras import fix_inlet_states\n", "\n", "tear_guesses = fix_inlet_states(m)" - ], - "outputs": [], - "execution_count": 29 + ] }, { "cell_type": "markdown", @@ -870,17 +872,17 @@ }, { "cell_type": "code", + "execution_count": 30, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.235882200Z", "start_time": "2026-02-25T17:35:04.227743300Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ], - "outputs": [], - "execution_count": 30 + ] }, { "cell_type": "markdown", @@ -891,12 +893,14 @@ }, { "cell_type": "code", + "execution_count": 31, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.257770300Z", "start_time": "2026-02-25T17:35:04.236888500Z" } }, + "outputs": [], "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", @@ -913,9 +917,7 @@ "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ], - "outputs": [], - "execution_count": 31 + ] }, { "cell_type": "markdown", @@ -926,18 +928,18 @@ }, { "cell_type": "code", + "execution_count": 32, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.268846Z", "start_time": "2026-02-25T17:35:04.260299600Z" } }, + "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ], - "outputs": [], - "execution_count": 32 + ] }, { "cell_type": "markdown", @@ -961,38 +963,38 @@ }, { "cell_type": "code", + "execution_count": 33, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.278171500Z", "start_time": "2026-02-25T17:35:04.269857200Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ], - "outputs": [], - "execution_count": 33 + ] }, { "cell_type": "code", + "execution_count": 34, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.288481300Z", "start_time": "2026-02-25T17:35:04.279196300Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ], - "outputs": [], - "execution_count": 34 + ] }, { "cell_type": "markdown", @@ -1003,18 +1005,18 @@ }, { "cell_type": "code", + "execution_count": 35, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.302496300Z", "start_time": "2026-02-25T17:35:04.289482700Z" } }, + "outputs": [], "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ], - "outputs": [], - "execution_count": 35 + ] }, { "cell_type": "markdown", @@ -1034,35 +1036,33 @@ }, { "cell_type": "code", + "execution_count": 36, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.312730200Z", "start_time": "2026-02-25T17:35:04.305395100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ], - "outputs": [], - "execution_count": 36 + ] }, { "cell_type": "code", + "execution_count": 37, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:04.340811100Z", "start_time": "2026-02-25T17:35:04.313761800Z" - } + }, + "tags": [ + "solution" + ] }, - "source": [ - "print(degrees_of_freedom(m))" - ], "outputs": [ { "name": "stdout", @@ -1072,7 +1072,9 @@ ] } ], - "execution_count": 37 + "source": [ + "print(degrees_of_freedom(m))" + ] }, { "cell_type": "markdown", @@ -1096,25 +1098,28 @@ ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "First, we will highlight some helpful functions that are used in the initialization process." + "metadata": {}, + "source": [ + "First, we will highlight some helpful functions that are used in the initialization process." + ] }, { + "cell_type": "code", + "execution_count": 39, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.386344500Z", "start_time": "2026-02-25T17:35:04.376804600Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def initialize_unit(unit):\n", " from idaes.core.util.exceptions import InitializationError\n", " import idaes.logger as idaeslog\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", @@ -1126,9 +1131,7 @@ " except InitializationError:\n", " solver = get_solver(solver_options=optarg)\n", " solver.solve(unit)" - ], - "outputs": [], - "execution_count": 39 + ] }, { "cell_type": "markdown", @@ -1145,13 +1148,15 @@ ] }, { + "cell_type": "code", + "execution_count": 40, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.394802500Z", "start_time": "2026-02-25T17:35:04.386344500Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def automatic_propagation(m, tear_guesses):\n", "\n", @@ -1176,9 +1181,7 @@ " print(o[0].name)\n", "\n", " seq.run(m, initialize_unit)" - ], - "outputs": [], - "execution_count": 40 + ] }, { "cell_type": "markdown", @@ -1190,16 +1193,18 @@ ] }, { + "cell_type": "code", + "execution_count": 41, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.404491500Z", "start_time": "2026-02-25T17:35:04.396317500Z" } }, - "cell_type": "code", - "source": "# automatic_propagation(m, tear_guesses)", "outputs": [], - "execution_count": 41 + "source": [ + "# automatic_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1213,12 +1218,14 @@ }, { "cell_type": "code", + "execution_count": 42, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:04.417815100Z", "start_time": "2026-02-25T17:35:04.404995800Z" } }, + "outputs": [], "source": [ "def manual_propagation(m, tear_guesses):\n", " from idaes.core.util.initialization import propagate_state\n", @@ -1234,7 +1241,6 @@ " print(f\"The DOF is {degrees_of_freedom(m)} after setting the tear stream\")\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " # \"tol\": 1e-10,\n", @@ -1275,7 +1281,6 @@ " propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product\n", "\n", " optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 300,\n", " \"tol\": 1e-8,\n", @@ -1291,9 +1296,7 @@ " print(\n", " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", " )" - ], - "outputs": [], - "execution_count": 42 + ] }, { "cell_type": "markdown", @@ -1308,13 +1311,13 @@ }, { "cell_type": "code", + "execution_count": 43, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.145125500Z", "start_time": "2026-02-25T17:35:04.419335500Z" } }, - "source": "manual_propagation(m, tear_guesses)", "outputs": [ { "name": "stdout", @@ -1327,7 +1330,9 @@ ] } ], - "execution_count": 43 + "source": [ + "manual_propagation(m, tear_guesses)" + ] }, { "cell_type": "markdown", @@ -1347,22 +1352,21 @@ }, { "cell_type": "code", + "execution_count": 44, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.161129400Z", "start_time": "2026-02-25T17:35:07.146644300Z" } }, + "outputs": [], "source": [ "optarg = {\n", - " \"nlp_scaling_method\": \"user-scaling\",\n", " \"OF_ma57_automatic_scaling\": \"yes\",\n", " \"max_iter\": 1000,\n", " \"tol\": 1e-8,\n", "}" - ], - "outputs": [], - "execution_count": 44 + ] }, { "cell_type": "markdown", @@ -1385,43 +1389,43 @@ }, { "cell_type": "code", + "execution_count": 45, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.170980400Z", "start_time": "2026-02-25T17:35:07.163178100Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "\n", "# Solve the model" - ], - "outputs": [], - "execution_count": 45 + ] }, { "cell_type": "code", + "execution_count": 46, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.272798500Z", "start_time": "2026-02-25T17:35:07.170980400Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Create the solver object\n", "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=False)" - ], - "outputs": [], - "execution_count": 46 + ] }, { "cell_type": "markdown", @@ -1441,20 +1445,20 @@ }, { "cell_type": "code", + "execution_count": 48, "metadata": { - "tags": [ - "noauto" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.302463Z", "start_time": "2026-02-25T17:35:07.282944100Z" - } + }, + "tags": [ + "noauto" + ] }, + "outputs": [], "source": [ "# m.fs.visualize(\"HDA-Flowsheet\")" - ], - "outputs": [], - "execution_count": 48 + ] }, { "cell_type": "markdown", @@ -1465,15 +1469,13 @@ }, { "cell_type": "code", + "execution_count": 49, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.337983600Z", "start_time": "2026-02-25T17:35:07.303479400Z" } }, - "source": [ - "m.fs.report()" - ], "outputs": [ { "name": "stdout", @@ -1485,21 +1487,23 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", - " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 4.0452e-12 2.0426e-12 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7847e-07\n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.34190 1.6736e-09 1.8681e-09 1.0000e-08 0.26712 1.1139e-06 1.1140e-06 1.0000e-08 0.094878 2.7852e-07\n", " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 1.6901 2.0320 2.0320 1.7648 1.0000e-08 1.4119 1.4119 0.17224 1.0000e-08 0.35297\n", " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.22733 0.13374 0.63390 0.76595 0.76595 0.76595 0.76595 0.66001 0.66001 0.76595\n", " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.77267 0.86626 0.36610 0.23405 0.23405 0.23405 0.23405 0.33999 0.33999 0.23405\n", " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 0.024624 0.058732 0.17408 0.084499 0.084499 0.084499 0.084499 0.82430 0.82430 0.084499\n", " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.028601 0.15380 0.038450 0.0088437 0.0088437 0.0088435 0.0088435 0.17570 0.17570 0.0088435\n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.0794e-08 1.0794e-08 0.18592\n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.1844e-08 4.1844e-08 0.72074\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.33283 0.27683 0.16148 0.18592 0.18592 0.18592 0.18592 1.8212e-08 1.8212e-08 0.18592\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.61394 0.51064 0.62599 0.72074 0.72074 0.72074 0.72074 4.8268e-08 4.8268e-08 0.72074\n", " Temperature kelvin 303.20 303.20 324.51 600.00 771.86 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", "====================================================================================\n" ] } ], - "execution_count": 49 + "source": [ + "m.fs.report()" + ] }, { "cell_type": "markdown", @@ -1510,25 +1514,25 @@ }, { "cell_type": "code", + "execution_count": 50, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.355013500Z", "start_time": "2026-02-25T17:35:07.346055600Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 419008.28211932775\n" + "operating cost = $ 419008.28599155403\n" ] } ], - "execution_count": 50 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ] }, { "cell_type": "markdown", @@ -1539,18 +1543,13 @@ }, { "cell_type": "code", + "execution_count": 52, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.469810Z", "start_time": "2026-02-25T17:35:07.452663800Z" } }, - "source": [ - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))" - ], "outputs": [ { "name": "stdout", @@ -1571,33 +1570,28 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.26712 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.76595 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.23405 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.084499 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0088437 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18592 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.72074 - - \n", - " Temperature kelvin 325.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", - " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", - " temperature kelvin - 375.00 375.00 \n", - " pressure pascal - 1.5000e+05 1.5000e+05 \n", + " flow_mol_phase Liq mole / second 0.26712 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.76595 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.23405 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.084499 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0088437 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18592 1.8212e-08 1.8212e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.72074 4.8268e-08 4.8268e-08 \n", + " temperature kelvin 325.00 375.00 375.00 \n", + " pressure pascal 3.5000e+05 1.5000e+05 1.5000e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.8242963521555953\n" + "benzene purity = 0.8242963399526197\n" ] } ], - "execution_count": 52 + "source": [ + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))" + ] }, { "cell_type": "markdown", @@ -1608,28 +1602,20 @@ }, { "cell_type": "code", + "execution_count": 54, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.503351300Z", "start_time": "2026-02-25T17:35:07.487979400Z" } }, - "source": [ - "from idaes.core.util.tables import (\n", - " create_stream_table_dataframe,\n", - " stream_table_dataframe_to_string,\n", - ")\n", - "\n", - "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", - "print(stream_table_dataframe_to_string(st))" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Units Reactor Light Gases\n", - "Total Molar Flowrate Liq mole / second 2.0426e-12 1.0000e-08 \n", + "Total Molar Flowrate Liq mole / second 1.8681e-09 1.0000e-08 \n", "Total Molar Flowrate Vap mole / second 2.0320 1.7648 \n", "Total Mole Fraction ('Liq', 'benzene') dimensionless 0.63390 0.76595 \n", "Total Mole Fraction ('Liq', 'toluene') dimensionless 0.36610 0.23405 \n", @@ -1642,7 +1628,15 @@ ] } ], - "execution_count": 54 + "source": [ + "from idaes.core.util.tables import (\n", + " create_stream_table_dataframe,\n", + " stream_table_dataframe_to_string,\n", + ")\n", + "\n", + "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", + "print(stream_table_dataframe_to_string(st))" + ] }, { "cell_type": "markdown", @@ -1675,17 +1669,17 @@ }, { "cell_type": "code", + "execution_count": 55, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.523495700Z", "start_time": "2026-02-25T17:35:07.513232100Z" } }, + "outputs": [], "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ], - "outputs": [], - "execution_count": 55 + ] }, { "cell_type": "markdown", @@ -1698,21 +1692,21 @@ }, { "cell_type": "code", + "execution_count": 56, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.538051100Z", "start_time": "2026-02-25T17:35:07.528058900Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.R101.outlet.temperature.fix(600)\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ], - "outputs": [], - "execution_count": 56 + ] }, { "cell_type": "markdown", @@ -1733,38 +1727,38 @@ }, { "cell_type": "code", + "execution_count": 57, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.568196100Z", "start_time": "2026-02-25T17:35:07.545899Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ], - "outputs": [], - "execution_count": 57 + ] }, { "cell_type": "code", + "execution_count": 58, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.578318700Z", "start_time": "2026-02-25T17:35:07.571295800Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ], - "outputs": [], - "execution_count": 58 + ] }, { "cell_type": "markdown", @@ -1782,18 +1776,18 @@ }, { "cell_type": "code", + "execution_count": 60, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.627054600Z", "start_time": "2026-02-25T17:35:07.619525700Z" } }, + "outputs": [], "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ], - "outputs": [], - "execution_count": 60 + ] }, { "cell_type": "markdown", @@ -1813,37 +1807,39 @@ }, { "cell_type": "code", + "execution_count": 61, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.638684200Z", "start_time": "2026-02-25T17:35:07.630104900Z" - } + }, + "tags": [ + "exercise" + ] }, - "source": "# Todo: Set the bounds for flash 101 outlet temperature", "outputs": [], - "execution_count": 61 + "source": [ + "# Todo: Set the bounds for flash 101 outlet temperature" + ] }, { "cell_type": "code", + "execution_count": 62, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.652892600Z", "start_time": "2026-02-25T17:35:07.643756900Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)" - ], - "outputs": [], - "execution_count": 62 + ] }, { "cell_type": "markdown", @@ -1854,20 +1850,20 @@ }, { "cell_type": "code", + "execution_count": 63, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.662831700Z", "start_time": "2026-02-25T17:35:07.654919400Z" } }, + "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ], - "outputs": [], - "execution_count": 63 + ] }, { "cell_type": "markdown", @@ -1878,12 +1874,14 @@ }, { "cell_type": "code", + "execution_count": 64, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.673507300Z", "start_time": "2026-02-25T17:35:07.666381200Z" } }, + "outputs": [], "source": [ "m.fs.overhead_loss = Constraint(\n", " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", @@ -1892,9 +1890,7 @@ " <= 0.20\n", " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ], - "outputs": [], - "execution_count": 64 + ] }, { "cell_type": "markdown", @@ -1914,32 +1910,34 @@ }, { "cell_type": "code", + "execution_count": 65, "metadata": { - "tags": [ - "exercise" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.688400300Z", "start_time": "2026-02-25T17:35:07.677541500Z" - } + }, + "tags": [ + "exercise" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ], - "outputs": [], - "execution_count": 65 + ] }, { "cell_type": "code", + "execution_count": 66, "metadata": { - "tags": [ - "solution" - ], "ExecuteTime": { "end_time": "2026-02-25T17:35:07.707964Z", "start_time": "2026-02-25T17:35:07.699126100Z" - } + }, + "tags": [ + "solution" + ] }, + "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", @@ -1948,9 +1946,7 @@ " ]\n", " >= 0.15\n", ")" - ], - "outputs": [], - "execution_count": 66 + ] }, { "cell_type": "markdown", @@ -1961,17 +1957,17 @@ }, { "cell_type": "code", + "execution_count": 67, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.718982700Z", "start_time": "2026-02-25T17:35:07.711201900Z" } }, + "outputs": [], "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ], - "outputs": [], - "execution_count": 67 + ] }, { "cell_type": "markdown", @@ -1985,15 +1981,17 @@ }, { "cell_type": "code", + "execution_count": 68, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.837157700Z", "start_time": "2026-02-25T17:35:07.721454600Z" } }, - "source": "results = solver.solve(m, tee=False)", "outputs": [], - "execution_count": 68 + "source": [ + "results = solver.solve(m, tee=False)" + ] }, { "cell_type": "markdown", @@ -2006,33 +2004,19 @@ }, { "cell_type": "code", + "execution_count": 70, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.883912Z", "start_time": "2026-02-25T17:35:07.847804400Z" } }, - "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))\n", - "\n", - "print()\n", - "print(\"Product flow rate and purity in F102\")\n", - "\n", - "m.fs.F102.report()\n", - "\n", - "print()\n", - "print(\"benzene purity = \", value(m.fs.purity))\n", - "\n", - "print()\n", - "print(\"Overhead loss in F101\")\n", - "m.fs.F101.report()" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "operating cost = $ 312674.2367538264\n", + "operating cost = $ 312674.23682387645\n", "\n", "Product flow rate and purity in F102\n", "\n", @@ -2050,29 +2034,19 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 0.28812 - - \n", - " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.75463 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.24537 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.032748 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.0032478 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.21614 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.74786 - - \n", - " Temperature kelvin 301.88 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", - " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", - " temperature kelvin - 362.93 362.93 \n", - " pressure pascal - 1.0500e+05 1.0500e+05 \n", + " flow_mol_phase Liq mole / second 0.28812 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second 1.0000e-08 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.75463 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.24537 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.032748 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.0032478 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.21614 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.74786 4.0825e-08 4.0825e-08 \n", + " temperature kelvin 301.88 362.93 362.93 \n", + " pressure pascal 3.5000e+05 1.0500e+05 1.0500e+05 \n", "====================================================================================\n", "\n", - "benzene purity = 0.818829588839798\n", + "benzene purity = 0.8188295887582271\n", "\n", "Overhead loss in F101\n", "\n", @@ -2090,31 +2064,35 @@ "------------------------------------------------------------------------------------\n", " Stream Table\n", " Units Inlet Vapor Outlet Liquid Outlet\n", - " Total Molar Flowrate Liq mole / second 2.6849e-12 - - \n", - " Total Molar Flowrate Vap mole / second 1.9480 - - \n", - " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.57381 - - \n", - " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.42619 - - \n", - " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.13952 - - \n", - " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.039059 - - \n", - " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.18417 - - \n", - " Total Mole Fraction ('Vap', 'methane') dimensionless 0.63725 - - \n", - " Temperature kelvin 600.00 - - \n", - " Pressure pascal 3.5000e+05 - - \n", - " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", - " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", - " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", - " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", - " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", - " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", - " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", - " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", - " temperature kelvin - 301.88 301.88 \n", - " pressure pascal - 3.5000e+05 3.5000e+05 \n", + " flow_mol_phase Liq mole / second 2.6866e-12 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second 1.9480 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless 0.57381 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless 0.42619 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless 0.13952 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless 0.039059 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless 0.18417 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless 0.63725 0.74786 0.74786 \n", + " temperature kelvin 600.00 301.88 301.88 \n", + " pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 \n", "====================================================================================\n" ] } ], - "execution_count": 70 + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))\n", + "\n", + "print()\n", + "print(\"Product flow rate and purity in F102\")\n", + "\n", + "m.fs.F102.report()\n", + "\n", + "print()\n", + "print(\"benzene purity = \", value(m.fs.purity))\n", + "\n", + "print()\n", + "print(\"Overhead loss in F101\")\n", + "m.fs.F101.report()" + ] }, { "cell_type": "markdown", @@ -2125,27 +2103,13 @@ }, { "cell_type": "code", + "execution_count": 72, "metadata": { "ExecuteTime": { "end_time": "2026-02-25T17:35:07.924695400Z", "start_time": "2026-02-25T17:35:07.893574600Z" } }, - "source": [ - "print(\n", - " f\"\"\"Optimal Values:\n", - "\n", - "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", - "\n", - "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", - "\n", - "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", - "\n", - "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", - "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", - "\"\"\"\n", - ")" - ], "outputs": [ { "name": "stdout", @@ -2165,7 +2129,21 @@ ] } ], - "execution_count": 72 + "source": [ + "print(\n", + " f\"\"\"Optimal Values:\n", + "\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", + "\n", + "R101 heat duty = {value(m.fs.R101.heat_duty[0]):.3f} W\n", + "\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", + "\n", + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ] } ], "metadata": { @@ -2185,7 +2163,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.12.0" } }, "nbformat": 4,