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

Contributes script to install IDAES and COIN solvers on Google Colab #1237

Merged
merged 16 commits into from
Aug 17, 2023

Conversation

adowling2
Copy link
Contributor

@adowling2 adowling2 commented Aug 9, 2023

Contributes script to install IDAES and COIN solvers on Google Colab

Fixes

Summary/Motivation:

  • Installing IDAES (and solvers via get-extensions) is a little quirky on Colab
  • We've used (a prior version of) this script for teaching with Google Colab for over a year with >40 student testers

Changes proposed in this PR:

  • Contributes one 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.

Contributes script to install IDAES and COIN solvers on Google Colab
@adowling2
Copy link
Contributor Author

adowling2 commented Aug 9, 2023

@jsiirola is another good reviewer.

I'd like feedback on:

  • How should this get tested?
  • Are we okay with the API / level of commenting?
  • Are we okay with leaving the install_CBC, etc. backup methods? The default usage is just to run install_idaes() and then install_ipopt(). install_ipopt will first try get-extensions which actually installs many solvers.

Copy link
Contributor

@jsiirola jsiirola left a comment

Choose a reason for hiding this comment

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

In addition to the specific comments below, there are several general changes that should be made:

  • fix the identified spelling errors
  • remove the logic for direct downloads from ampl.com
  • I would suggest replacing (all?) uses of os.system with subprocess.run

'''

# Check if idaes is available. If not, install it
if not package_available("idaes"):
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think that looking for the IDAES executable is the best way to see if the package has been installed. Rather, I would recommend:

try:
    import idaes
    print("IDAES found! No need to install.")
except ImportError:
    print("Installing idaes via pip...")
    subprocess.run([sys.executable, "-m", "pip", "install", "-q", "idaes_pse"], check=True)
    print("idaes was successfully installed")
    subprocess.run(["idaes", "--version'], check=True)

also note in the above:

  • the use of subprocess.run() with check=True
  • the use of an explicit argument list and not a single string
  • the use of sys.executable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the great suggestion. I implemented it.

Comment on lines 100 to 109
# Add symbolic link for idaes solvers
# These are needed for Colab to find the solvers
os.system("ln -s /root/.idaes/bin/ipopt ipopt")
os.system("ln -s /root/.idaes/bin/k_aug k_aug")
os.system("ln -s /root/.idaes/bin/couenne couenne")
os.system("ln -s /root/.idaes/bin/bonmin bonmin")
os.system("ln -s /root/.idaes/bin/cbc cbc")
os.system("ln -s /root/.idaes/bin/clp clp")
os.system("ln -s /root/.idaes/bin/ipopt_l1 ipopt_l1")
os.system("ln -s /root/.idaes/bin/dot_sens dot_sens")
Copy link
Contributor

Choose a reason for hiding this comment

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

This is only needed for the command_with_output below and if you don't import idaes in your script. I generally don't think that it is a good idea to link / move installed files. Instead it would be better to either update where Pyomo looks for executables, or add /root/.idaes/bin to the os.environ['PATH']

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I got the PATH alternative to work. Thanks for the great suggestion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, I want to make these solvers accessible without import idaes for two reasons:

  • Have the script print the solver versions, which is a good check and helpful for debugging.
  • Reuse this script in workshops/classes/tutorials that introduce Pyomo. In my experience, skipping import idaes is easier with brand-new Pyomo users.

# As a backup, try copying the executable from AMPL
if on_colab():
print("Installing Ipopt via zip file...")
os.system('wget -N -q "https://ampl.com/dl/open/ipopt/ipopt-linux64.zip"')
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that direct (anonymous) wget from ampl.com no longer works: AMPL requires all downloads to first authenticate using a valid user account.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just removed these.

@adowling2
Copy link
Contributor Author

@jsiirola This is ready for you to review.

@dangunter You might also find this helpful/interesting. I've been using a script like this to install Pyomo and IDAES in Google Colab for my graduate elective.

@adowling2
Copy link
Contributor Author

@ksbeattie @lbianchi-lbl I have black on the most updated version of this one file on my computer; it said no changes. I also confirmed I do not have any uncommitted or unpushed changes. Yet the black test is still failing.

For everyone: I tested this on Google Colab (hence several commits this morning.) I am not sure how to automate testing in Google Colab or if that is really even needed.

@adowling2 adowling2 self-assigned this Aug 10, 2023
@andrewlee94
Copy link
Member

@adowling2 black is very temperamental - you need to have the correct version of black installed as the formatting changes slightly from version to version.

@adowling2
Copy link
Contributor Author

@andrewlee94 Now that I have your attention, do you want to review this quickly?

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.

This looks OK to me, but I am no expert on this sort of stuff.

@codecov
Copy link

codecov bot commented Aug 10, 2023

Codecov Report

Patch coverage has no change and project coverage change: -0.01% ⚠️

Comparison is base (deacf4c) 76.83% compared to head (733c94a) 76.83%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1237      +/-   ##
==========================================
- Coverage   76.83%   76.83%   -0.01%     
==========================================
  Files         390      390              
  Lines       61942    61942              
  Branches    11398    11398              
==========================================
- Hits        47595    47592       -3     
- Misses      11878    11882       +4     
+ Partials     2469     2468       -1     

see 1 file with indirect coverage changes

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

Copy link
Contributor

@jsiirola jsiirola left a comment

Choose a reason for hiding this comment

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

This is getting pretty close.

scripts/colab_helper.py Outdated Show resolved Hide resolved

def _check_available(executable_name):
"""Utility to check in an executable is available"""
return shutil.which(executable_name) or os.path.isfile(executable_name)
Copy link
Contributor

@jsiirola jsiirola Aug 10, 2023

Choose a reason for hiding this comment

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

(More of an FYI than an action) This is fine for collab (where we know it is Linux-based). However, a more portable approach would be to use something akin to Pyomo's pyomo.common.fileutils.Executable (which is what Pyomo uses for locating executables)

Comment on lines +83 to +86
["idaes", "--version"], check=True, capture_output=True, text=True
)
print(v.stdout)
print(v.stderr)
Copy link
Contributor

Choose a reason for hiding this comment

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

If you are just going to print out the output anyway, why bother with capture=True?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't get the output to show up without using capture. I'm also new to using subprocess.

Copy link
Contributor Author

@adowling2 adowling2 Aug 10, 2023

Choose a reason for hiding this comment

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

My quick research (again, I know little about subprocess) suggests I'd need to use Popen to get access to STDOUT or STDERR.

Copy link
Contributor

Choose a reason for hiding this comment

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

On the terminal, the output comes to the terminal if you don't specify capture_output. I wonder if this is different for the collab environment? If that's the case, we want to at least be consistent and capture/print for all subprocess calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I expected that behavior on Colab, but no luck when testing in a cell.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsiirola, I like your suggestion. I added a verbose flag to display the captured pip, idaes get-extensions, etc. output

@ksbeattie ksbeattie added the Priority:Normal Normal Priority Issue or PR label Aug 10, 2023
Copy link
Contributor

@lbianchi-lbl lbianchi-lbl left a comment

Choose a reason for hiding this comment

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

I think having this script here can be valuable for users of IDAES on Google Colab in addition to and beyond the original audience. A few general thoughts:

  • I don't think there's a way to test this automatically (without an unreasonable amount of effort)
  • Since the script is tested and will continue to be used in the future, I think we can pragmatically rely on this "outside testing" to detect possible breaking changes
  • However, since we're adding code to the repository that's not being tested by the CI, before merging, we should:
    • Identify who the maintainer(s) of this script will be, e.g. by adding an entry to the CODEOWNERS file
    • Add some kind of simple versioning information to the script itself (since the script won't have access to either the Git history or the idaes version at runtime)

"https://raw.githubusercontent.com/adowling2/idaes-pse/colab-install-script/scripts/colab_helper.py"

"""

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd recommend to add some versioning information, e.g. by adding a line here with __version__ = "0.23.8" (or any other date-based versioning schema).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great suggestion

@adowling2
Copy link
Contributor Author

adowling2 commented Aug 10, 2023

@jsiirola @lbianchi-lbl Thanks for the suggested changes. This should be ready.

Changes:

  • Capture all subprocess output. Added verbose flag to toggle on output for pip install, idaes get-extensions, etc.
  • Added a version
  • Added my name in CODEOWNERS
  • Retested on Google Colab

@adowling2
Copy link
Contributor Author

@jsiirola @lbianchi-lbl This is ready for your re-review.

@lbianchi-lbl lbianchi-lbl merged commit 210844b into IDAES:main Aug 17, 2023
31 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.

5 participants