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 NaCl recovery value to crystallizer model #1120

Merged
merged 12 commits into from
Sep 8, 2023

Conversation

Zhuoran29
Copy link
Contributor

@Zhuoran29 Zhuoran29 commented Sep 6, 2023

Fixes/Resolves:

Added the recovery value of NaCl from the crystallization product

Summary/Motivation:

  • For economic analysis purpose, specifically in SETO project, it is necessary to account for the recovery value.
  • In some cases the recovery value would result in a negative operating cost, which is not allowed in the current costing package. Associated change was made to it as well.

Changes proposed in this PR:

  • Changed the domain of total_operating_cost to pyo.Reals.
  • Update the solutions in three testing files that were impacted by the change above.
    • watertap/examples/flowsheets/nf_dspmde/tests/test_nf.py
    • watertap/examples/flowsheets/full_treatment_train/analysis/tests/test_flowsheets.py
    • watertap/examples/flowsheets/full_treatment_train/flowsheet_components/chemistry/tests/test_posttreatment.py
  • Added a defined flow of NaCl in the crystallizer unit costing model
  • Added testing functions in the crystallizer tester file

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.

@codecov
Copy link

codecov bot commented Sep 6, 2023

Codecov Report

Patch coverage: 100.00% and no project coverage change.

Comparison is base (3b37c9c) 94.92% compared to head (a17266d) 94.92%.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1120   +/-   ##
=======================================
  Coverage   94.92%   94.92%           
=======================================
  Files         331      331           
  Lines       32501    32504    +3     
=======================================
+ Hits        30852    30855    +3     
  Misses       1649     1649           
Files Changed Coverage Δ
watertap/costing/watertap_costing_package.py 100.00% <ø> (ø)
watertap/costing/units/crystallizer.py 100.00% <100.00%> (ø)

☔ View full report in Codecov by Sentry.

📢 Have feedback on the report? Share it here.

"recovery": [
m.fs.NF.nfUnit.recovery_vol_phase[0.0, "Liq"] * 100,
73.47934090302432,
94.99999441324391,
],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test has a larger difference in results. @bknueven @adam-a-a

Copy link
Contributor

Choose a reason for hiding this comment

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

@Zhuoran29 can you double check the value of the total_operating_cost here, both before and after the change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bknueven Sure, before the change total_operating_cost = 2369.18, and after the change total_operating_cost = 2429.43.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was able to do this myself:
current main: total_operating_cost: 2369.1822124750583
With this change: total_operating_cost: 2429.430766595918

It's actually a bit higher, funnily enough ...

Copy link
Contributor

Choose a reason for hiding this comment

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

This change also brings the converged values without bypass much closer to those with by pass:

No Bypass, main:

total_operating_cost: 2369.182212475059
Optimal cost 0.16810666231247273
Optimal NF pressure (Bar) 6.560034522531212
Optimal area (m2) 285.7101510399154
Optimal nf recovery (%) 73.48423398501477
Feed hardness (mg/L as CaCO3) 1016.1545749479138
Product hardness (mg/L as CaCO3) 199.9999928713816
Disposal hardness (mg/L as CaCO3) 3277.997368528139

No Bypass, with this change:

total_operating_cost: 2429.430766595918
Optimal cost 0.15058960529129017
Optimal NF pressure (Bar) 8.12906860029318
Optimal area (m2) 423.89564182114776
Optimal nf recovery (%) 94.99999441324391
Feed hardness (mg/L as CaCO3) 1016.1545749479138
Product hardness (mg/L as CaCO3) 199.9995335609493
Disposal hardness (mg/L as CaCO3) 16523.08212268398

With Bypass with / without this change:

total_operating_cost: 2217.7019485486526
Optimal cost 0.1376886456374725
Optimal NF pressure (Bar) 6.702781481688757
Optimal area (m2) 419.7559334394971
Optimal nf recovery (%) 94.99999897882932
bypass (%) 10.592027708476932
Feed hardness (mg/L as CaCO3) 1016.1240639142685
Product hardness (mg/L as CaCO3) 199.9999851467023
Disposal hardness (mg/L as CaCO3) 18456.17762054043

@@ -252,7 +252,7 @@ def build_process_costs(self):
)
self.total_operating_cost = pyo.Var(
initialize=1e3,
domain=pyo.NonNegativeReals,
domain=pyo.Reals,
doc="Total operating cost",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is where I changed the domain in the costing package and it creates some different solutions in the testing files below, one of which has a difference larger than 10%. @bknueven @adam-a-a

Copy link
Contributor

@bknueven bknueven left a comment

Choose a reason for hiding this comment

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

I guess my meta-question on this PR is if we've set other aggregates to have the domain NonNegativeReals and if they should all be changed to Reals.

Probably should be part of a follow-up, however.

Copy link
Contributor

@bknueven bknueven left a comment

Choose a reason for hiding this comment

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

I am happy -- the change seems to resolve a local optima issue in the NF flowsheet. See: #1120 (comment)

I am unconcerned about the other test values changing -- the affected tests have always been a bit sensitive to otherwise inconsequential changes.

@bknueven bknueven marked this pull request as ready for review September 7, 2023 17:01
@Zhuoran29
Copy link
Contributor Author

I guess my meta-question on this PR is if we've set other aggregates to have the domain NonNegativeReals and if they should all be changed to Reals.

Probably should be part of a follow-up, however.

I see total_capital_cost and maintenance_labor_chemical_operating_cost are also constrained as NonNegativeReals, which should be the case in practice, but it's interesting to see if changing them to Reals has impact on the local optimal solutions as well. I tried that real quick in 'test_nf.py' but I don't see a change in total_operating_cost.

@bknueven
Copy link
Contributor

bknueven commented Sep 7, 2023

I guess my meta-question on this PR is if we've set other aggregates to have the domain NonNegativeReals and if they should all be changed to Reals.
Probably should be part of a follow-up, however.

I see total_capital_cost and maintenance_labor_chemical_operating_cost are also constrained as NonNegativeReals, which should be the case in practice, but it's interesting to see if changing them to Reals has impact on the local optimal solutions as well. I tried that real quick in 'test_nf.py' but I don't see a change in total_operating_cost.

It looks like the zero order costing package doesn't bound these quantities at all. I would prefer not to have redundant bounds on variables. I will resolve this in #1122.

@bknueven
Copy link
Contributor

bknueven commented Sep 7, 2023

I would like to merge this before #1122.

@bknueven bknueven mentioned this pull request Sep 7, 2023
8 tasks
Comment on lines +75 to +92
9.505698559578499e-07, rel=1e-3
)
assert model.fs.ideal_naocl_mixer_unit.outlet.flow_mol[0].value == pytest.approx(
25.000025535888078, rel=1e-3
)
assert model.fs.ideal_naocl_mixer_unit.outlet.mole_frac_comp[
0, "OCl_-"
].value == pytest.approx(1.6123004572288052e-07, rel=1e-3)
].value == pytest.approx(5.107133802822922e-07, rel=1e-3)

assert model.fs.ideal_naocl_chlorination_unit.free_chlorine.value == pytest.approx(
2, rel=1e-3
)
assert model.fs.ideal_naocl_chlorination_unit.outlet.mole_frac_comp[
0, "OCl_-"
].value == pytest.approx(5.0027242332010015e-08, rel=1e-3)
].value == pytest.approx(4.5088044031726496e-07, rel=1e-3)
assert model.fs.ideal_naocl_chlorination_unit.outlet.mole_frac_comp[
0, "H_+"
].value == pytest.approx(1.49011416785194e-10, rel=1e-3)
].value == pytest.approx(5.4260427865375997e-11, rel=1e-3)
Copy link
Contributor

Choose a reason for hiding this comment

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

since these are all close to 0, wonder if they should have absolute tolerances instead of relative tolerances (what we typically want to use for ~0 values).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea good catch, I think that should be the case.

Comment on lines +23 to 29
"lcow": [m.fs.costing.LCOW, 0.15058960529129017],
"pressure": [m.fs.NF.pump.outlet.pressure[0] / 1e5, 8.13],
"area": [m.fs.NF.nfUnit.area, 423.8956418211484],
"recovery": [
m.fs.NF.nfUnit.recovery_vol_phase[0.0, "Liq"] * 100,
73.47934090302432,
94.99999441324391,
],
Copy link
Contributor

Choose a reason for hiding this comment

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

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 - nice job!

@ksbeattie ksbeattie added the Priority:Normal Normal Priority Issue or PR label Sep 7, 2023
Change to absolute tolerance for zeros.

Co-authored-by: Adam Atia <aatia@keylogic.com>
@ksbeattie ksbeattie enabled auto-merge (squash) September 7, 2023 20:26
@bknueven bknueven enabled auto-merge (squash) September 8, 2023 00:00
@bknueven bknueven merged commit c49bf30 into watertap-org:main Sep 8, 2023
24 checks passed
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