Add Solver Config Option to IPOPT Convergence Analysis#1606
Add Solver Config Option to IPOPT Convergence Analysis#1606dallan-keylogic merged 5 commits intoIDAES:mainfrom
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1606 +/- ##
=======================================
Coverage 76.85% 76.85%
=======================================
Files 394 394
Lines 63241 63246 +5
Branches 10359 10360 +1
=======================================
+ Hits 48604 48608 +4
- Misses 12188 12191 +3
+ Partials 2449 2447 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
dallan-keylogic
left a comment
There was a problem hiding this comment.
Please avoid mutable objects as default arguments.
idaes/core/util/model_diagnostics.py
Outdated
| CONFIG = CACONFIG() | ||
|
|
||
| def __init__(self, model, **kwargs): | ||
| def __init__(self, model, solver=SolverFactory("ipopt"), **kwargs): |
There was a problem hiding this comment.
Having mutable Python objects as default arguments causes trouble, because it uses the same object each time the function is called.
In [1]: def append_a(lst=[]):
...: lst.append("a")
...: return lst
...:
In [2]: lst = append_a()
In [3]: lst = append_a()
In [4]: lst
Out[4]: ['a', 'a']
We might expect the second instance of lst to contain a single element because it's using the default argument of [], but because it uses the same instance of the list object each time the function is called, it contains two elements.
The way we work around this is by using None as the default argument, then creating an object if the argument is None:
def __init__(self, model, solver=None, **kwargs):
if solver is None:
solver = SolverFactory("ipopt")
Also, if you expect a solver object to be passed, you should make solver_obj the name of the function argument. It would be even better to add it as a config argument instead of an argument to __init__.
I assume that ipopt_watertap has some set of default options different than those in IDAES.
There was a problem hiding this comment.
Thanks Doug! I didn't realize default arguments for each instance builds on top of the previous ones. I've set the default solver argument to None.
I'm not too familiar with the differences between ipopt and ipopt-watertap other than the fact that using ipopt has caused issues in the past.
There was a problem hiding this comment.
You can find WaterTap solver options in the repo: https://github.com/watertap-org/watertap-solvers/tree/main
There was a problem hiding this comment.
@MarcusHolly It's a tricky issue, and it would have caused major headaches for me if I hadn't been alerted to it by senior team members.
idaes/core/util/model_diagnostics.py
Outdated
| CONFIG = CACONFIG() | ||
|
|
||
| def __init__(self, model, **kwargs): | ||
| def __init__(self, model, solver=None, **kwargs): |
There was a problem hiding this comment.
Could you please also change the name from solver to solver_obj? Typically if we had solver as the default argument, we'd pass the string "ipopt" instead of an IPOPT solver object.
Summary/Motivation:
Addresses an issue in watertap-org/watertap#1563 where tests are passing locally but failing on GitHub. This is believed to be a result of this tool defaulting the solver to ipopt, whereas WaterTAP requires ipopt-watertap.
Changes proposed in this PR:
Legal Acknowledgement
By contributing to this software project, I agree to the following terms and conditions for my contribution: