-
Notifications
You must be signed in to change notification settings - Fork 84
Print properties contained in Seawater prop model #1686
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
4bdc330
6f66821
e737d35
1f60e87
4b2b128
00a7880
966a7cb
27a4cd2
b60568e
46d0c29
7c7581b
eeff5ed
81b7357
f1ac879
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 |
|---|---|---|
|
|
@@ -15,3 +15,4 @@ | |
| assert_no_degrees_of_freedom, | ||
| assert_degrees_of_freedom, | ||
| ) | ||
| from .property_helpers import get_property_metadata | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| ################################################################################# | ||
| # 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/" | ||
| ################################################################################# | ||
|
|
||
| import pandas as pd | ||
| from idaes.core.util.config import is_physical_parameter_block | ||
|
|
||
|
|
||
| def get_property_metadata(prop_pkg): | ||
| """Get all supported properties from a WaterTAP/IDAES property package as a Pandas DataFrame.""" | ||
| try: | ||
| assert is_physical_parameter_block(prop_pkg) | ||
| except: | ||
| raise TypeError("get_property_metadata expected a PhysicalParameterBlock.") | ||
| metadata = prop_pkg.get_metadata() | ||
| pd.set_option("display.max_rows", None) | ||
| df = pd.DataFrame( | ||
| { | ||
| "Description": [v._doc for v in metadata.properties], | ||
| "Name": [v._name for v in metadata.properties], | ||
| "Units": [str(v._units) for v in metadata.properties], | ||
| } | ||
| ) | ||
| return df | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| ################################################################################# | ||
| # 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/" | ||
| ################################################################################# | ||
|
|
||
| import pytest | ||
| import pandas as pd | ||
| from idaes.core.base.property_base import ( | ||
| PhysicalParameterBlock as DummyPhysicalParameterBlock, | ||
| ) | ||
| from watertap.core.util.property_helpers import get_property_metadata | ||
|
|
||
|
|
||
| # Dummy classes to mimic WaterTAP metadata structure | ||
| class DummyProp: | ||
| def __init__(self, name, units, doc): | ||
| self._name = name | ||
| self._units = units | ||
| self._doc = doc | ||
|
|
||
|
|
||
| class DummyMetadata: | ||
| def __init__(self): | ||
| self.properties = [ | ||
| DummyProp("flow_mass", "kg/s", "Mass flow rate"), | ||
| DummyProp("temperature", "K", "Stream temperature"), | ||
| ] | ||
|
|
||
|
|
||
| class DummyPropPkg(DummyPhysicalParameterBlock): | ||
| def __init__(self): | ||
| self.component = ["dummy_component"] | ||
|
|
||
| def get_metadata(self): | ||
| return DummyMetadata() | ||
|
|
||
|
|
||
| @pytest.mark.unit | ||
| def test_get_property_metadata(): | ||
| pkg = DummyPropPkg() | ||
| df = get_property_metadata(pkg) | ||
|
|
||
| # Check type | ||
| assert isinstance(df, pd.DataFrame) | ||
|
|
||
| # Check columns | ||
| expected_cols = ["Description", "Name", "Units"] | ||
| assert list(df.columns) == expected_cols | ||
|
|
||
| # Check content | ||
| assert "flow_mass" in df["Name"].values | ||
| assert "temperature" in df["Name"].values | ||
| assert "kg/s" in df["Units"].values |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,10 +12,6 @@ | |
| """ | ||
| Initial property package for seawater system | ||
| """ | ||
|
|
||
| # Import Python libraries | ||
| import idaes.logger as idaeslog | ||
|
|
||
| # Import Pyomo libraries | ||
| from pyomo.environ import ( | ||
| Constraint, | ||
|
|
@@ -43,6 +39,7 @@ | |
| MaterialBalanceType, | ||
| EnergyBalanceType, | ||
| ) | ||
| from idaes.core.base.property_set import PropertyMetadata, PropertySetBase | ||
| from idaes.core.base.components import Solute, Solvent | ||
| from idaes.core.base.phases import LiquidPhase | ||
| from idaes.core.util.constants import Constants | ||
|
|
@@ -51,7 +48,7 @@ | |
| revert_state_vars, | ||
| solve_indexed_blocks, | ||
| ) | ||
| from watertap.core.solvers import get_solver | ||
| import idaes.logger as idaeslog | ||
| from idaes.core.util.model_statistics import ( | ||
| degrees_of_freedom, | ||
| number_unfixed_variables, | ||
|
|
@@ -62,7 +59,11 @@ | |
| PropertyPackageError, | ||
| ) | ||
| import idaes.core.util.scaling as iscale | ||
|
|
||
| # Import WaterTAP libraries | ||
| from watertap.core.solvers import get_solver | ||
| from watertap.core.util.scaling import transform_property_constraints | ||
| from watertap.core.util.property_helpers import get_property_metadata | ||
|
|
||
| # Set up logger | ||
| _log = idaeslog.getLogger(__name__) | ||
|
|
@@ -736,9 +737,24 @@ def build(self): | |
| self.set_default_scaling("diffus_phase_comp", 1e9) | ||
| self.set_default_scaling("boiling_point_elevation_phase", 1e0, index="Liq") | ||
|
|
||
| def list_properties(self): | ||
| """ | ||
| Return seawater property package metadata as a pandas DataFrame. | ||
| """ | ||
| df = get_property_metadata(self).reset_index(drop=True) | ||
| return df | ||
|
|
||
| def print_properties(self): | ||
| """ | ||
| Print seawater property package metadata to the console. | ||
| """ | ||
| df = get_property_metadata(self).reset_index(drop=True) | ||
| print(df.to_string(index=False)) # Pretty print without index | ||
|
|
||
| @classmethod | ||
| def define_metadata(cls, obj): | ||
| """Define properties supported and units.""" | ||
| obj.define_property_set(SeawaterPropertySet) | ||
| obj.add_properties( | ||
| { | ||
| "flow_mass_phase_comp": {"method": None}, | ||
|
|
@@ -759,11 +775,6 @@ def define_metadata(cls, obj): | |
| "cp_mass_phase": {"method": "_cp_mass_phase"}, | ||
| "therm_cond_phase": {"method": "_therm_cond_phase"}, | ||
| "diffus_phase_comp": {"method": "_diffus_phase_comp"}, | ||
| } | ||
| ) | ||
|
|
||
| obj.define_custom_properties( | ||
| { | ||
| "dens_mass_solvent": {"method": "_dens_mass_solvent"}, | ||
| "osm_coeff": {"method": "_osm_coeff"}, | ||
| "enth_flow": {"method": "_enth_flow"}, | ||
|
|
@@ -804,7 +815,7 @@ def fix_initialization_states(self): | |
| # Constraint on water concentration at outlet - unfix in these cases | ||
| for b in self.values(): | ||
| if b.config.defined_state is False: | ||
| b.conc_mol_comp["H2O"].unfix() | ||
| b.flow_mass_phase_comp["Liq", "H2O"].unfix() | ||
|
|
||
| def initialize( | ||
| self, | ||
|
|
@@ -1789,3 +1800,127 @@ def calculate_scaling_factors(self): | |
|
|
||
| # transforming constraints | ||
| transform_property_constraints(self) | ||
|
|
||
|
Collaborator
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 realize this is normal in IDAES but I find this way of creating data very verbose.
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. Me too, but given the current IDAES functionality and the way metadata is handled and reported back, this was the cleaner way of producing the list of property names actually supported on this property model, without the noise. Open to suggestions if there's a slicker approach, but this is meant a quick fix, with planned refinement in subsequent PRs (this quarter).
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 feel like this is redundant, don't the pyomo vars in the property block contain all of the same information? Would it not be easier to make a list of the "vars" you want to display and simply grab it? |
||
|
|
||
| class SeawaterPropertySet(PropertySetBase): | ||
| """ | ||
| This object defines properties within the seawater property model. | ||
| """ | ||
|
|
||
| flow_mass_phase_comp = PropertyMetadata( | ||
| name="flow_mass_phase_comp", | ||
| doc="Mass flow rate", | ||
| units=pyunits.kg / pyunits.s, | ||
| ) | ||
| temperature = PropertyMetadata( | ||
| name="temperature", | ||
| doc="Temperature", | ||
| units=pyunits.K, | ||
| ) | ||
| pressure = PropertyMetadata( | ||
| name="pressure", | ||
| doc="Pressure", | ||
| units=pyunits.Pa, | ||
| ) | ||
| mass_frac_phase_comp = PropertyMetadata( | ||
| name="mass_frac", | ||
| doc="Mass fraction", | ||
| units=pyunits.dimensionless, | ||
| ) | ||
| dens_mass_phase = PropertyMetadata( | ||
| name="dens_mass_phase", | ||
| doc="Mass density of solution", | ||
| units=pyunits.kg * pyunits.m**-3, | ||
| ) | ||
|
|
||
| flow_vol = PropertyMetadata( | ||
| name="flow_vol", | ||
| doc="Total volumetric flow rate", | ||
| units=pyunits.m**3 / pyunits.s, | ||
| ) | ||
| flow_vol_phase = PropertyMetadata( | ||
| name="flow_vol_phase", | ||
| doc="Volumetric flow rate of phase", | ||
| units=pyunits.m**3 / pyunits.s, | ||
| ) | ||
| conc_mass_phase_comp = PropertyMetadata( | ||
| name="conc_mass_phase_como", | ||
| doc="Mass concentration", | ||
| units=pyunits.kg * pyunits.m**-3, | ||
| ) | ||
| flow_mol_phase_comp = PropertyMetadata( | ||
| name="flow_mol", | ||
| doc="Molar flowrate", | ||
| units=pyunits.mol / pyunits.s, | ||
| ) | ||
| mole_frac_phase_comp = PropertyMetadata( | ||
| name="mole_frac_phase_comp", | ||
| doc="Mole fraction", | ||
| units=pyunits.dimensionless, | ||
| ) | ||
| molality_phase_comp = PropertyMetadata( | ||
| name="molality_phase_comp", | ||
| doc="Molality", | ||
| units=pyunits.mole / pyunits.kg, | ||
| ) | ||
| visc_d_phase = PropertyMetadata( | ||
| name="visc_d_phase", | ||
| doc="Dynamic viscosity", | ||
| units=pyunits.Pa * pyunits.s, | ||
| ) | ||
| pressure_osm_phase = PropertyMetadata( | ||
| name="pressure_osm_phase", | ||
| doc="Osmotic pressure", | ||
| units=pyunits.Pa, | ||
| ) | ||
| enth_mass_phase = PropertyMetadata( | ||
| name="enth_mass_phase", | ||
| doc="Specific enthalpy", | ||
| units=pyunits.J * pyunits.kg**-1, | ||
| ) | ||
| pressure_sat = PropertyMetadata( | ||
| name="pressure_sat", | ||
| doc="Vapor pressure", | ||
| units=pyunits.Pa, | ||
| ) | ||
| cp_mass_phase = PropertyMetadata( | ||
| name="cp_mass", | ||
| doc="Specific heat capacity", | ||
| units=pyunits.J / (pyunits.kg * pyunits.K), | ||
| ) | ||
| therm_cond_phase = PropertyMetadata( | ||
| name="therm_cond_phase", | ||
| doc="Thermal conductivity", | ||
| units=pyunits.W / (pyunits.m * pyunits.K), | ||
| ) | ||
| diffus_phase_comp = PropertyMetadata( | ||
| name="diffus_phase_comp", | ||
| doc="Diffusivity", | ||
| units=pyunits.m**2 / pyunits.s, | ||
| ) | ||
|
|
||
| dens_mass_solvent = PropertyMetadata( | ||
| name="dens_mass_solvent", | ||
| doc="Mass density of pure water", | ||
| units=pyunits.kg * pyunits.m**-3, | ||
| ) | ||
| osm_coeff = PropertyMetadata( | ||
| name="osm_coeff", | ||
| doc="Osmotic coefficient", | ||
| units=pyunits.dimensionless, | ||
| ) | ||
| enth_flow = PropertyMetadata( | ||
| name="enth_flow", | ||
| doc="Enthalpy flow", | ||
| units=pyunits.J / pyunits.s, | ||
| ) | ||
| dh_vap_mass = PropertyMetadata( | ||
| name="dh_vap_mass", | ||
| doc="Latent heat of vaporization", | ||
| units=pyunits.J * pyunits.kg**-1, | ||
| ) | ||
| boiling_point_elevation_phase = PropertyMetadata( | ||
| name="boiling_point_elevation_phase", | ||
| doc="Boiling point elevation temperature", | ||
| units=pyunits.K, | ||
| ) | ||
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.
can this fail?
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.
Here's the method (below). I suppose we can add a check for the
_metadataattribute and raise an exception if it doesn't exist. Do you know of a better check to ensure the property model is a property model? Another idea is to check whether the prop_pkg input is a ParameterBlock.