Skip to content
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

Add MD 0D #1105

Merged
merged 48 commits into from
Sep 29, 2023
Merged

Add MD 0D #1105

merged 48 commits into from
Sep 29, 2023

Conversation

ElmiraShamlou
Copy link
Contributor

Fixes/Resolves:

(replace this with the issue # fixed or resolved, if no issue exists then a brief statement of what this PR does)

Summary/Motivation:

Changes proposed in this PR:

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.

@adam-a-a adam-a-a marked this pull request as draft August 16, 2023 23:03
@codecov
Copy link

codecov bot commented Aug 17, 2023

Codecov Report

Attention: 39 lines in your changes are missing coverage. Please review.

Comparison is base (164a775) 94.88% compared to head (be3aa17) 94.86%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1105      +/-   ##
==========================================
- Coverage   94.88%   94.86%   -0.02%     
==========================================
  Files         336      340       +4     
  Lines       33269    33931     +662     
==========================================
+ Hits        31566    32189     +623     
- Misses       1703     1742      +39     
Files Coverage Δ
...atertap/unit_models/MD/membrane_distillation_0D.py 98.64% <98.64%> (ø)
watertap/unit_models/MD/MD_channel_0D.py 94.80% <94.80%> (ø)
watertap/unit_models/MD/MD_channel_base.py 94.32% <94.32%> (ø)
...ertap/unit_models/MD/membrane_distillation_base.py 92.13% <92.13%> (ø)

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ksbeattie ksbeattie added the Priority:Normal Normal Priority Issue or PR label Aug 17, 2023
Comment on lines +201 to +222
if type == "hot_ch":
state_args_properties_out = state_args["hot_outlet"]

self.properties_out.initialize(
state_args=state_args_properties_out,
outlvl=outlvl,
optarg=optarg,
solver=solver,
)
elif type == "cold_ch":
state_args_properties_out = state_args["cold_outlet"]

self.properties_out.initialize(
state_args=state_args_properties_out,
outlvl=outlvl,
optarg=optarg,
solver=solver,
)
else:
raise ConfigurationError(
"Either hot_ch or cold_ch must be set in the configuration."
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it one or the other? Shouldn't both be initialized? Also, it looks like you would need pass strings to type here, which I don't think we want to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cold outlet and hot outlet are initialized differently based on inlet

Comment on lines +65 to +86
CONFIG.declare(
"dynamic",
ConfigValue(
default=False,
domain=In([False]),
description="Dynamic model flag - must be False",
doc="""Indicates whether this model will be dynamic or not.
**default** - False. Membrane units do not yet support dynamic
behavior.""",
),
)
CONFIG.declare(
"has_holdup",
ConfigValue(
default=False,
domain=In([False]),
description="Holdup construction flag - must be False",
doc="""Indicates whether holdup terms should be constructed or not.
**default** - False. Membrane units do not have defined volume, thus
this must be False.""",
),
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason that we need dynamic and has_holdup in the main config block as well as in the config template for hot and cold channels? I would think you could eliminate these 2 from config_template, but maybe there is some reason for doing this.

Comment on lines +336 to +361
_CONFIG_Template.declare(
"property_package_vapor",
ConfigValue(
default=useDefault,
domain=is_physical_parameter_block,
description="Property package to use for control volume",
doc="""Property parameter object used to define property calculations,
**default** - useDefault.
**Valid values:** {
**useDefault** - use default package from parent model or flowsheet,
**PhysicalParameterObject** - a PhysicalParameterBlock object.}""",
),
)
_CONFIG_Template.declare(
"property_package_args_vapor",
ConfigBlock(
implicit=True,
description="Arguments to use for constructing property packages",
doc="""A ConfigBlock with arguments to be passed to a property block(s)
and used when constructing these,
**default** - None.
**Valid values:** {
see property package for documentation.}""",
),
)

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any need to have property_package_vapor specified for each channel, or can we just specify it once on the main CONFIG block?

Copy link
Contributor

Choose a reason for hiding this comment

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

From the tests, I see you need to specify twice (once for each channel). Maybe there is some alternative configuration where you might want to consider 2 different vapor packages that I am not seeing, but from my current perspective, I don't see any immediate use cases for having 2 different vapor property packages.

Comment on lines +278 to +318
@self.Constraint(
self.flowsheet().config.time,
self.difference_elements,
doc="hot side evaporation enthalpy flux",
)
def eq_flux_hot_enth(b, t, x):
return (
b.flux_enth_hot[t, x]
== b.flux_mass[t, x]
* b.hot_ch.properties_vapor[t, x].enth_mass_phase["Vap"]
)

@self.Constraint(
self.flowsheet().config.time,
self.difference_elements,
doc="cold side evaporation enthalpy flux",
)
def eq_flux_cold_enth(b, t, x):
return (
b.flux_enth_cold[t, x]
== b.flux_mass[t, x]
* b.cold_ch.properties_vapor[t, x].enth_mass_phase["Vap"]
)

@self.Expression(
self.flowsheet().config.time,
doc="Average hot side enthalpy flux expression",
)
def flux_enth_hot_avg(b, t):
return (
sum(b.flux_enth_hot[t, x] for x in self.difference_elements) / self.nfe
)

@self.Expression(
self.flowsheet().config.time,
doc="Average cold side enthalpy flux expression",
)
def flux_enth_cold_avg(b, t):
return (
sum(b.flux_enth_cold[t, x] for x in self.difference_elements) / self.nfe
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't these be consolidated and put in MD_channel_base (or MD_channel_0D)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mass and heat fluxes connect the channels but are not defined for each individual channel. Even the eq_flux_hot_enth and eq_flux_cold_enth are defined by the mass flux that connects the hot and cold channels.

Comment on lines 214 to 230
self.flux_enth_hot = Var(
self.flowsheet().config.time,
self.difference_elements,
initialize=1e3,
bounds=(1e-4, 1e5),
units=pyunits.J * pyunits.s**-1 * pyunits.m**-2,
doc="hot side evaporation enthalpy flux",
)

self.flux_enth_cold = Var(
self.flowsheet().config.time,
self.difference_elements,
initialize=1e3,
bounds=(1e-4, 1e5),
units=pyunits.J * pyunits.s**-1 * pyunits.m**-2,
doc="cold side condensation enthalpy flux",
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't these go in one of the channel files? Then, you could later reference hot_ch.flux_enth or cold_ch.flux_enth

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only these two variables, but not their associated constraints, may go to MD_channel_base.

Comment on lines +362 to +363
CONFIG.declare("hot_ch", _CONFIG_Template(doc="hot channel config arguments"))
CONFIG.declare("cold_ch", _CONFIG_Template(doc="cold channel config arguments"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor preference here, but I think it'd be better to fully spell out hot_channel and cold_channel.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can do this in future PRs as it requires changing many lines of code.

@lbianchi-lbl
Copy link
Contributor

@ElmiraShamlou is planning to work on some details and documentation but overall should be soon ready for review.

@ElmiraShamlou ElmiraShamlou marked this pull request as ready for review September 20, 2023 12:03
Copy link
Contributor

@TimBartholomew TimBartholomew left a comment

Choose a reason for hiding this comment

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

I primarily reviewed the documentation and test file and it looks good.

One suggestion I have that would be for a later PR would be to change "ch" to "channel". Renaming won't be that big of deal, but lots of lines of code would change.

Copy link
Contributor

@savannahsakhai savannahsakhai left a comment

Choose a reason for hiding this comment

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

I attempted to look through all of the files. It looks good to me.

I made comments on a few possible typos.

):
super().add_state_blocks(has_phase_equilibrium=has_phase_equilibrium)

# quack like a 1D model
Copy link
Contributor

Choose a reason for hiding this comment

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

What is meant here? I think there is a typo.

Copy link
Contributor Author

@ElmiraShamlou ElmiraShamlou Sep 28, 2023

Choose a reason for hiding this comment

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

@savannahsakhai Even though the model is 0D, it intentionally includes a length domain and inlet/outlet properties, aligning with the flow direction, much like a 1D model would

solute_set,
doc="Concentration polarization modulus",
)
def eq_cp_modulus(b, t, x, j): # pylint: disable=function-redefined
Copy link
Contributor

Choose a reason for hiding this comment

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

Was this comment meant to be left in?

Comment on lines +152 to +153
# self.config.hot_ch.property_package.phase_list,
# self.config.hot_ch.property_package.component_list,
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these meant to be left this way? Are they serving a purpose?

Copy link
Contributor

Choose a reason for hiding this comment

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

We typically delete commented code, so we can delete in a subsequent PR.

Comment on lines +240 to +256
self.flux_enth_hot = Var(
self.flowsheet().config.time,
self.difference_elements,
initialize=1e3,
bounds=(1e-10, 1e5),
units=pyunits.J * pyunits.s**-1 * pyunits.m**-2,
doc="hot side evaporation enthalpy flux",
)

self.flux_enth_cold = Var(
self.flowsheet().config.time,
self.difference_elements,
initialize=1e3,
bounds=(1e-10, 1e5),
units=pyunits.J * pyunits.s**-1 * pyunits.m**-2,
doc="cold side condensation enthalpy flux",
)
Copy link
Contributor

@savannahsakhai savannahsakhai Sep 28, 2023

Choose a reason for hiding this comment

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

The variables directly above this use units_meta. Is there a reason that these variables do not follow the same convention? I believe this only occurs a few times across the files.

m.fs.unit.permeability_coef.fix(1e-10)
m.fs.unit.membrane_thickness.fix(1e-4)
m.fs.unit.membrane_tc.fix(0.2)
# m.fs.unit.hot_ch.cp_modulus.fix(1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this comment meant to be left this way?

Copy link
Contributor

@adam-a-a adam-a-a left a comment

Choose a reason for hiding this comment

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

LGTM - @ElmiraShamlou please create an issue tracking any comments here that we would consider in a follow-up PR.

@ksbeattie ksbeattie added Priority:High High Priority Issue or PR and removed Priority:Normal Normal Priority Issue or PR labels Sep 28, 2023
@lbianchi-lbl lbianchi-lbl enabled auto-merge (squash) September 29, 2023 01:13
@lbianchi-lbl lbianchi-lbl merged commit a40bd78 into watertap-org:main Sep 29, 2023
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority:High High Priority Issue or PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants