-
Notifications
You must be signed in to change notification settings - Fork 84
Create unit model tools directory and move calculate_operating_pressure
#1699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2819acd
6d9e6d4
969a60b
6794e0a
57e66f8
d6a172e
e97d196
24bc795
85e04e5
8ccdb28
91b60b7
a78f2f0
d2dd303
ea50b84
02e94fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| ################################################################################# | ||
| # WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, | ||
| # through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, | ||
| # National Renewable Energy Laboratory, and National Energy Technology | ||
| # Laboratory (subject to receipt of any required approvals from the U.S. Dept. | ||
| # of Energy). All rights reserved. | ||
| # | ||
| # Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license | ||
| # information, respectively. These files are also available online at the URL | ||
| # "https://github.com/watertap-org/watertap/" | ||
| ################################################################################# | ||
|
|
||
| from .reverse_osmosis import * |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| ################################################################################# | ||
| # WaterTAP Copyright (c) 2020-2024, The Regents of the University of California, | ||
| # through Lawrence Berkeley National Laboratory, Oak Ridge National Laboratory, | ||
| # National Renewable Energy Laboratory, and National Energy Technology | ||
| # Laboratory (subject to receipt of any required approvals from the U.S. Dept. | ||
| # of Energy). All rights reserved. | ||
| # | ||
| # Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license | ||
| # information, respectively. These files are also available online at the URL | ||
| # "https://github.com/watertap-org/watertap/" | ||
| ################################################################################# | ||
| """ | ||
| This module contains functions to be used with WaterTAP | ||
| ReverseOsmosis0D or ReverseOsmosis1D unit models. | ||
| """ | ||
|
|
||
| from pyomo.environ import ( | ||
| ConcreteModel, | ||
| check_optimal_termination, | ||
| value, | ||
| ) | ||
| from idaes.core.util.initialization import solve_indexed_blocks | ||
|
|
||
| from watertap.property_models.seawater_prop_pack import SeawaterStateBlockData | ||
| from watertap.property_models.NaCl_prop_pack import NaClStateBlockData | ||
| from watertap.property_models.NaCl_T_dep_prop_pack import ( | ||
| NaClStateBlockData as NaClTDepStateBlockData, | ||
| ) | ||
| from watertap.core import MembraneChannel0DBlock, MembraneChannel1DBlock | ||
| from watertap.core.solvers import get_solver | ||
|
|
||
|
|
||
| __all__ = ["calculate_operating_pressure"] | ||
|
|
||
|
|
||
| def calculate_operating_pressure( | ||
| state_block=None, | ||
| over_pressure_factor=1.15, | ||
| water_recovery_mass=0.5, | ||
| salt_passage=0, | ||
| solver=None, | ||
| ): | ||
| """ | ||
| Estimate operating pressure for RO unit model given the following arguments: | ||
|
|
||
| Arguments: | ||
| state_block: the state block of the RO feed that has the non-pressure state variables set to desired values (default=None) | ||
| over_pressure_factor: the amount of operating pressure above the brine osmotic pressure represented as a fraction (default=1.15) | ||
| water_recovery_mass: the mass-based fraction of inlet H2O that becomes permeate (default=0.5) | ||
| salt_passage: the mass-based fraction of inlet salt that becomes permeate (default=0) | ||
| solver: solver object to be used (default=None) | ||
| """ | ||
|
|
||
| if any( | ||
| isinstance(state_block, cls) | ||
| for cls in [MembraneChannel0DBlock, MembraneChannel1DBlock] | ||
| ): | ||
| state_block = state_block.properties[0, 0] | ||
|
|
||
| if not any( | ||
| isinstance(state_block, cls) | ||
| for cls in [SeawaterStateBlockData, NaClStateBlockData, NaClTDepStateBlockData] | ||
| ): | ||
| raise TypeError( | ||
| "state_block must be created with SeawaterParameterBlock, NaClParameterBlock, or NaClTDepParameterBlock" | ||
| ) | ||
|
|
||
| if not 0 <= salt_passage < 0.999: | ||
| raise ValueError("salt_passage argument must be between 0 and 0.999") | ||
|
|
||
| if not 1e-3 < water_recovery_mass < 0.999: | ||
| raise ValueError("water_recovery_mass argument must be between 0.001 and 0.999") | ||
|
|
||
| if not over_pressure_factor >= 1.0: | ||
| raise ValueError( | ||
| "over_pressure_factor argument must be greater than or equal to 1.0" | ||
| ) | ||
|
|
||
| comp = state_block.params.solute_set.first() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming that we are limiting this to single solute prop models right now, I’d recommend just checking the solute_set had a length no greater than 1. If greater than 1, raise exception since not supported yet
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the state block type check above, is it possible to get to this point with a state block where
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would extend it a bit.
|
||
|
|
||
| if comp not in ["NaCl", "TDS"]: | ||
| raise ValueError( | ||
| f"salt_passage calculation only supported for NaCl or TDS components but found {comp}" | ||
| ) | ||
|
|
||
| if solver is None: | ||
| solver = get_solver() | ||
|
|
||
| tmp = ConcreteModel() # create temporary model | ||
| prop = state_block.config.parameters | ||
|
|
||
| tmp.feed = prop.build_state_block([0]) | ||
| tmp.feed[0].pressure_osm_phase | ||
|
|
||
| # specify state block | ||
| tmp.feed[0].flow_mass_phase_comp["Liq", "H2O"].fix( | ||
| value(state_block.flow_mass_phase_comp["Liq", "H2O"]) | ||
| * (1 - water_recovery_mass) | ||
| ) | ||
| tmp.feed[0].flow_mass_phase_comp["Liq", comp].fix( | ||
| value(state_block.flow_mass_phase_comp["Liq", comp]) * (1 - salt_passage) | ||
| ) | ||
| tmp.feed[0].temperature.fix(value(state_block.temperature)) | ||
| tmp.feed[0].pressure.fix(101325) | ||
|
|
||
| # solve state block | ||
| results = solve_indexed_blocks(solver, [tmp.feed]) | ||
|
|
||
| if not check_optimal_termination(results): | ||
| raise RuntimeError( | ||
| "Failed to solve temporary state block for operating pressure" | ||
| ) | ||
|
|
||
| op_pressure = value(tmp.feed[0].pressure_osm_phase["Liq"]) * over_pressure_factor | ||
|
|
||
| return op_pressure | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One note about location--since I noticed the discussion on #1689: the tools folder originally had parameter sweep, in addition to oli_api and some associated oli utilities, the latter of which were then moved to utilities.
To me, this fits more closely with what we have under utilities. The only exception is that this a utility in the context of unit models. I suppose this is subjective, but if you are shooting for consistency alongside historical context, there it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean
watertap.core.util? I suppose it is subjective and also dependent on what the difference between a "tool" and a "utility" function is.To me,
from watertap.tools.unit_models import ____(or evenfrom watertap.tools import _____) is more obvious and accessible. I would moderately fight for this hill but not die on it.