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

Reformulate solubility_products constraints #1197

Merged
merged 23 commits into from
Jul 27, 2023
Merged

Conversation

lxhowl
Copy link
Contributor

@lxhowl lxhowl commented Jun 7, 2023

Fixes

pH-dependent solubility tests from WaterTAP

Summary/Motivation:

This solubility equilibrium constraint used a smoothing strategy to compare precipitate amount s and the solution state Q. Only one of s and Q can be greater than zero at any time. When s and Q differ in several orders of magnitude, the problem becomes hard to scale, especially when Q is in log form, the original formulation will sacrifice the accuracy of s, the precipitate amount, which could be very small (i.e., 1e-10) and important in water-related applications.

Fix outside of bounds warning in the initialization of pH-dependent solubility tests.

Changes proposed in this PR:

  • Normalize the precipitate amount s to be 0-1 with respect to its solubility product constant Ksp.

  • Update mole_frac_phase_comp bounds in FpcTP to be consistent with log_mole_frac_phase_comp bounds.

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.

Xinhong Liu added 2 commits May 26, 2023 12:20
… betweem s and Q.

Modified bounds of mole_frac_phase_comp to be consistent with those of log_mole_frac_phase_comp
@bknueven
Copy link
Contributor

bknueven commented Jun 7, 2023

For a bit more context, Xinhong has been working to make some of chemistry models in WaterTAP more stable. She found this issue with the formulation and came up with this fix to keep these smooth_max constraints scaled consistently.

Copy link
Member

@andrewlee94 andrewlee94 left a comment

Choose a reason for hiding this comment

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

I have a few questions about why you chose the formulation you did, as well as about consitency with other state definitions.

@andrewlee94
Copy link
Member

Also, the tests for the solubility product are all failing right now.

@adowling2
Copy link
Contributor

An alternate approach is to add a scaling factor to smooth_max.

scaled_smooth_max(0,x,scale) = scale*smooth_max(0, x/scale)

From an implementation perspective, I proposed adding an optional scale=1 argument to smooth_max that does this.

I also like @andrewlee94's suggestion about scaling variables carefully.

@ksbeattie ksbeattie added the Priority:Normal Normal Priority Issue or PR label Jun 8, 2023
@lxhowl lxhowl requested a review from andrewlee94 June 15, 2023 22:15
Copy link
Member

@andrewlee94 andrewlee94 left a comment

Choose a reason for hiding this comment

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

@lxhowl Changing the bounds on the mole fractions is not the correct way to address the variables outside of bounds warning - that is something that needs to be fixed in either the model or the tool that is setting the value outside the bounds. The value of 1w-20 was deliberately chose to avoid singularities, and this change is likely what caused the testing in the plate heat exchanger model to start failing.

@codecov
Copy link

codecov bot commented Jun 16, 2023

Codecov Report

Patch coverage: 84.61% and project coverage change: -0.01% ⚠️

Comparison is base (ad5b8ad) 76.84% compared to head (14cb740) 76.83%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1197      +/-   ##
==========================================
- Coverage   76.84%   76.83%   -0.01%     
==========================================
  Files         390      390              
  Lines       61875    61885      +10     
  Branches    11389    11391       +2     
==========================================
+ Hits        47547    47552       +5     
- Misses      11866    11871       +5     
  Partials     2462     2462              
Files Changed Coverage Δ
.../modular_properties/reactions/equilibrium_forms.py 87.21% <84.61%> (-0.59%) ⬇️

... and 1 file with indirect coverage changes

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

@lxhowl lxhowl requested a review from andrewlee94 June 16, 2023 15:22
@agarciadiego
Copy link
Contributor

@lxhowl if the user does not specify k_eq_ref how robust is the s_norm default value? Have we tested this with another example where the k_eq_ref is unknown? @andrewlee94 would it make more sense to have an if statement to use this formulation in case the user has an a priori knowledge of k_eq_ref

@andrewlee94
Copy link
Member

@agarciadiego I am leaning towards just having the one version - the old one already had a smoothing factor that the user should be setting anyway so this just adds more flexibility (and better scaling overall).

If we think it is necessary to keep both formulations, then I think they should be separate methods the user chooses from rather than an if statement in the code. An if buried in the code is far harder for the user to find and understand.

@lxhowl This discussion did remind me however that you need to update the documentation to reflect the new formulation and explain the new parameters (and how the user should adjust them).

@lxhowl
Copy link
Contributor Author

lxhowl commented Jun 16, 2023

@agarciadiego The tests I updated contains cases without k_eq_ref specified. I will add assertions for s_norm and s_scale default values checking.

The formulation of the updated s term is meant to keep it in the same level of accuracy as the Q term. It is doing a scaling down when s is large, so that we can preserve accuracy of Q term. And when s is small, it scale up to keep higher accuracy of s. As s_norm decreases, very low concentration s can be captured. The default s_norm value 1e-4 without k_eq_ref specified is set in considerations of common Ksp range 1e-37~1e-4.

@lxhowl lxhowl marked this pull request as draft June 20, 2023 19:30
@lxhowl lxhowl marked this pull request as ready for review June 20, 2023 21:54
@lbianchi-lbl
Copy link
Contributor

The test failures are likely due to #1215

Q = b.log_k_eq[r_idx] - e
# Q should be unitless due to log form

return s - smooth_max(0, s - Q, rblock.eps) == 0
return Q - smooth_max(0, Q - s, rblock.eps) == 0
Copy link
Member

Choose a reason for hiding this comment

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

If one or both Q and s need to be zero, could this just bee smooth min(Q, s) == 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Current expression goes Q-0.5(Q-s+|Q-s|) == 0 while the smooth min gives 0.5(Q+s-|Q-s|)==0. The complexity remains the same. The current expression keeps Q as a leading term, which might be easy for users to scale the solubility product with other equilibrium reactions.

Copy link
Member

Choose a reason for hiding this comment

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

@eslickj I think this formulation is correct - it is a bit more complicated than just one of Q or s needing to be zero.

Copy link
Member

Choose a reason for hiding this comment

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

@andrewlee94, I'm sure you are probably right. Can someone explain the difference to me? Why is this one preferred? I think both should work, but I may be missing something. To me, the the one in the code currently just seems convoluted.

Copy link
Member

Choose a reason for hiding this comment

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

@eslickj I cannot remember the details - I asked Larry Biegler to help with this is and this is the form he suggested.

@andrewlee94
Copy link
Member

@lxhowl Is this ready for re-review yet?

@lxhowl
Copy link
Contributor Author

lxhowl commented Jul 11, 2023

@lxhowl Is this ready for re-review yet?
YES, it is ready.

@lxhowl lxhowl requested a review from andrewlee94 July 20, 2023 18:46
@andrewlee94 andrewlee94 added enhancement New feature or request property packages Issues dealing with properties labels Jul 27, 2023
Copy link
Member

@andrewlee94 andrewlee94 left a comment

Choose a reason for hiding this comment

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

Looks good to me.

@andrewlee94 andrewlee94 enabled auto-merge (squash) July 27, 2023 18:11
@andrewlee94 andrewlee94 merged commit 52d7d5c into IDAES:main Jul 27, 2023
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Priority:Normal Normal Priority Issue or PR property packages Issues dealing with properties WaterTAP
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants