Skip to content

Conversation

@kurbansitterley
Copy link
Contributor

Fixes/Resolves:

Moves calculate_operating_pressure helper function from the RO w ERD flowsheet to a new directory for RO tools.

Summary/Motivation:

The calculate_operating_pressure helper function in the RO w ERD flowsheet is useful outside of that flowsheet. This PR moves that function to the newly created watertap/tools/unit_models where we could put this and other useful tools for specific unit models.

calculate_operating_pressure was modified from the current form to be able to accept:

  • seawater property model state blocks
  • NaCl property model state blocks
  • NaCl w temp dependence model state blocks
  • RO membrane channel 0D and 1D control volumes

It also provides lower and upper bounds on acceptable arguments for water_recovery_mass and salt_passage.

Changes proposed in this PR:

  • create new subdirectory in watertap/tools called unit_models for unit model-specific helper functions
  • move and genericize calculate_operating_pressure helper function from the RO w ERD flowsheet
  • modify RO w ERD flowsheet to use this function
  • add test for this function

Legal Acknowledgement

By contributing to this software project, I agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the license terms described in the LICENSE.txt file at the top level of this directory.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

@@ -0,0 +1,113 @@
#################################################################################
Copy link
Contributor

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.

Copy link
Contributor Author

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 even from watertap.tools import _____) is more obvious and accessible. I would moderately fight for this hill but not die on it.

Comment on lines 78 to 83
if isinstance(feed_state_block, NaClStateBlockData) or isinstance(
feed_state_block, NaClTDepStateBlockData
):
comp = "NaCl"
if isinstance(feed_state_block, SeawaterStateBlockData):
comp = "TDS"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need these conditionals? Can't we just point to the component on component_list, as we do in unit models? A little complexity arises with MCAS, which we can add logic for, but can happen in a separate PR.

Instead, I'd propose a conditional check on the supported stateblockdata classes and raise an exception if it is not one of the anticipated prop model stateblocks.


def calculate_operating_pressure(
feed_state_block=None,
over_pressure=0.15,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
over_pressure=0.15,
over_pressure_factor=1.15,

I think it'd be more intuitive for the user if this were a factor representing what factor to multiply the brine osm press by, rather than the fraction that we have now.

Then you'd adjust the equation below and eliminate need to add 1 to the factor.

Comment on lines 88 to 91
tmp = ConcreteModel() # create temporary model
prop = feed_state_block.config.parameters

tmp.feed = prop.build_state_block([0])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nice. I wonder though if you could just clone the stateblock as your tmp model?

Suggested change
tmp = ConcreteModel() # create temporary model
prop = feed_state_block.config.parameters
tmp.feed = prop.build_state_block([0])
tmp = feed_state_block.clone()

Copy link
Contributor Author

@kurbansitterley kurbansitterley Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm let me try

update: doesn't work.

@kurbansitterley kurbansitterley self-assigned this Nov 24, 2025

print(over_pressure_factor, water_recovery_mass, salt_passage)

comp = [c for c in state_block.component_list if c != "H2O"][0]
Copy link
Contributor

@adam-a-a adam-a-a Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
comp = [c for c in state_block.component_list if c != "H2O"][0]
comp = state_block.params.solute_set

"over_pressure_factor argument must be greater than or equal to 1.0"
)

comp = state_block.params.solute_set.first()
Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 len(solute_set) > 1?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would extend it a bit.

  1. Check if there is osmotic_pressure available
  2. Check if there is single solute, if there is more then one, check if there is total_disolved_solids -> this will get MCAS to work although, it needs to have "seawater or NACL" properties for osmotic pressure enabled and density I think as well. This should cover most of our prop packs then.

@ksbeattie ksbeattie added the Priority:Normal Normal Priority Issue or PR label Dec 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Priority:Normal Normal Priority Issue or PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants