Skip to content

Commit 0b87513

Browse files
authored
Merge pull request #3417 from arjxn-py/install_odes
Extend `pybamm_install_odes` to include support for macOS systems
2 parents 0369f0c + 738cd57 commit 0b87513

File tree

12 files changed

+130
-42
lines changed

12 files changed

+130
-42
lines changed

.github/workflows/run_periodic_tests.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,50 @@ jobs:
153153
eval "$(pyenv init -)"
154154
pyenv activate pybamm-${{ matrix.python-version }}
155155
pyenv uninstall -f $( python --version )
156+
157+
test_install_odes:
158+
runs-on: ${{ matrix.os }}
159+
strategy:
160+
matrix:
161+
os: [ubuntu-latest, macos-latest]
162+
python-version: ["3.8", "3.9", "3.10", "3.11"]
163+
fail-fast: false
164+
name: Test pybamm_install_odes on ${{ matrix.os }}
165+
166+
steps:
167+
- name: Check out PyBaMM repository
168+
uses: actions/checkout@v4
169+
170+
- name: Install Linux system dependencies
171+
if: matrix.os == 'ubuntu-latest'
172+
run: |
173+
sudo apt-get update
174+
sudo apt-get install gfortran gcc libopenblas-dev
175+
- name: Install macOS system dependencies
176+
if: matrix.os == 'macos-latest'
177+
env:
178+
# Homebrew environment variables
179+
HOMEBREW_NO_INSTALL_CLEANUP: 1
180+
HOMEBREW_NO_AUTO_UPDATE: 1
181+
HOMEBREW_NO_COLOR: 1
182+
# Speed up CI
183+
NONINTERACTIVE: 1
184+
run: |
185+
brew analytics off
186+
brew install openblas
187+
brew reinstall gcc gfortran
188+
189+
- name: Set up Python ${{ matrix.python-version }}
190+
id: setup-python
191+
uses: actions/setup-python@v4
192+
with:
193+
python-version: ${{ matrix.python-version }}
194+
195+
- name: Install PyBaMM
196+
run: python -m pip install -e .
197+
198+
- name: Test pybamm_install_odes on ${{ matrix.os }}
199+
run: |
200+
python -m pip cache purge
201+
python -m pip install wget cmake
202+
pybamm_install_odes

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ KLU_module_deps
107107
# setup
108108
setup.log
109109

110+
# odes setup
111+
scikits_odes_setup.log
112+
110113
# test
111114
test.c
112115
test.json

.lycheeignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# a list of links/files to be ignored by lychee link checker (see workflow file)
2+
https://github.com/LLNL/sundials/releases/download/v%7BSUNDIALS_VERSION%7D/sundials-%7BSUNDIALS_VERSION%7D.tar.gz
23

34
# Errors in docs/source/user_guide/getting_started.md
45
file:///home/runner/work/PyBaMM/PyBaMM/docs/source/user_guide/api_docs

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Features
44

5+
- The `pybamm_install_odes` command now includes support for macOS systems and can be used to set up SUNDIALS and install the `scikits.odes` solver on macOS ([#3417](https://github.com/pybamm-team/PyBaMM/pull/3417))
56
- Added support for Python 3.12 ([#3531](https://github.com/pybamm-team/PyBaMM/pull/3531))
67
- Added method to get QuickPlot axes by variable ([#3596](https://github.com/pybamm-team/PyBaMM/pull/3596))
78
- Added custom experiment terminations ([#3596](https://github.com/pybamm-team/PyBaMM/pull/3596))

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ PyBaMM makes releases every four months and we use [CalVer](https://calver.org/)
104104

105105
PyBaMM is available on GNU/Linux, MacOS and Windows.
106106
We strongly recommend to install PyBaMM within a python virtual environment, in order not to alter any distribution python files.
107-
For instructions on how to create a virtual environment for PyBaMM, see [the documentation](https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#user-install).
107+
For instructions on how to create a virtual environment for PyBaMM, see [the documentation](https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#user-install).
108108

109109
### Using pip
110110

@@ -130,8 +130,8 @@ conda install -c conda-forge pybamm
130130

131131
Following GNU/Linux and macOS solvers are optionally available:
132132

133-
- [scikits.odes](https://scikits-odes.readthedocs.io/en/latest/)-based solver, see [the documentation](https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-scikits-odes-solver).
134-
- [jax](https://jax.readthedocs.io/en/latest/notebooks/quickstart.html)-based solver, see [the documentation](https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-jaxsolver).
133+
- [scikits.odes](https://scikits-odes.readthedocs.io/en/latest/)-based solver, see [the documentation](https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-scikits-odes-solver).
134+
- [jax](https://jax.readthedocs.io/en/latest/notebooks/quickstart.html)-based solver, see [the documentation](https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver).
135135

136136
## 📖 Citing PyBaMM
137137

docs/source/user_guide/installation/GNU-linux.rst renamed to docs/source/user_guide/installation/gnu-linux-mac.rst

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
GNU-Linux & MacOS
1+
GNU/Linux & macOS
22
=================
33

44
.. contents::
@@ -102,17 +102,15 @@ For an introduction to virtual environments, see
102102
Optional - scikits.odes solver
103103
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104104

105-
Users can install `scikits.odes <https://github.com/bmcage/odes>`__ in
106-
order to use the wrapped SUNDIALS ODE and DAE
107-
`solvers <https://docs.pybamm.org/en/latest/source/api/solvers/scikits_solvers.html>`__.
105+
Users can install `scikits.odes <https://github.com/bmcage/odes>`__ to utilize its interfaced SUNDIALS ODE and DAE `solvers <https://docs.pybamm.org/en/latest/source/api/solvers/scikits_solvers.html>`__ wrapped in PyBaMM.
108106

109107
.. note::
110108

111109
Currently, only GNU/Linux and macOS are supported.
112110

113111
.. note::
114112

115-
The ``scikits.odes`` solver is not supported on Python 3.12 yet, please refer to https://github.com/bmcage/odes/issues/162.
113+
The ``scikits.odes`` solver is not supported on Python 3.12 yet. Please refer to https://github.com/bmcage/odes/issues/162.
116114
There is support for Python 3.8, 3.9, 3.10, and 3.11.
117115

118116
.. tab:: GNU/Linux
@@ -121,10 +119,9 @@ order to use the wrapped SUNDIALS ODE and DAE
121119

122120
.. code:: bash
123121
124-
apt install libopenblas-dev
125-
pybamm_install_odes
122+
apt install libopenblas-dev
123+
pybamm_install_odes
126124
127-
The ``pybamm_install_odes`` command is installed with PyBaMM. It automatically downloads and installs the SUNDIALS library on your
128125
system (under ``~/.local``), before installing ``scikits.odes``. (Alternatively, one can install SUNDIALS without this script and run ``pip install pybamm[odes]`` to install ``pybamm`` with ``scikits.odes``.)
129126

130127
.. tab:: macOS
@@ -133,9 +130,29 @@ order to use the wrapped SUNDIALS ODE and DAE
133130

134131
.. code:: bash
135132
136-
pip install scikits.odes
133+
brew install openblas gcc gfortran
134+
pybamm_install_odes
137135
138-
Assuming that SUNDIALS was installed as described :ref:`above<user-install-label>`.
136+
The ``pybamm_install_odes`` command, installed with PyBaMM, automatically downloads and installs the SUNDIALS library on your
137+
system (under ``~/.local``), before installing `scikits.odes <https://scikits-odes.readthedocs.io/en/stable/installation.html>`__ . (Alternatively, one can install SUNDIALS without this script and run ``pip install pybamm[odes]`` to install ``pybamm`` with `scikits.odes <https://scikits-odes.readthedocs.io/en/stable/installation.html>`__)
138+
139+
To avoid installation failures when using ``pip install pybamm[odes]``, make sure to set the ``SUNDIALS_INST`` environment variable. If you have installed SUNDIALS using Homebrew, set the variable to the appropriate location. For example:
140+
141+
.. code:: bash
142+
143+
export SUNDIALS_INST=$(brew --prefix sundials)
144+
145+
Ensure that the path matches the installation location on your system. You can verify the installation location by running:
146+
147+
.. code:: bash
148+
149+
brew info sundials
150+
151+
Look for the installation path, and use that path to set the ``SUNDIALS_INST`` variable.
152+
153+
Note: The location where Homebrew installs SUNDIALS might vary based on the system architecture (ARM or Intel). Adjust the path in the ``export SUNDIALS_INST`` command accordingly.
154+
155+
To avoid manual setup of path the ``pybamm_install_odes`` is recommended for a smoother installation process, as it takes care of automatically downloading and installing the SUNDIALS library on your system.
139156

140157
Optional - JaxSolver
141158
~~~~~~~~~~~~~~~~~~~~

docs/source/user_guide/installation/index.rst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ Optional solvers
4747

4848
Following GNU/Linux and macOS solvers are optionally available:
4949

50-
* `scikits.odes <https://scikits-odes.readthedocs.io/en/latest/>`_ -based solver, see `Optional - scikits.odes solver <https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-scikits-odes-solver>`_.
51-
* `jax <https://jax.readthedocs.io/en/latest/notebooks/quickstart.html>`_ -based solver, see `Optional - JaxSolver <https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-jaxsolver>`_.
50+
* `scikits.odes <https://scikits-odes.readthedocs.io/en/latest/>`_ -based solver, see `Optional - scikits.odes solver <https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-scikits-odes-solver>`_.
51+
* `jax <https://jax.readthedocs.io/en/latest/notebooks/quickstart.html>`_ -based solver, see `Optional - JaxSolver <https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver>`_.
5252

5353
Dependencies
5454
------------
@@ -233,15 +233,15 @@ odes dependencies
233233

234234
Installable with ``pip install "pybamm[odes]"``
235235

236-
================================================================================================================================ ================== ================== =============================
237-
Dependency Minimum Version pip extra Notes
238-
================================================================================================================================ ================== ================== =============================
239-
`scikits.odes <https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-scikits-odes-solver>`__ \- odes For scikits ODE & DAE solvers
240-
================================================================================================================================ ================== ================== =============================
236+
======================================================================================================================================= ================== ================== =============================
237+
Dependency Minimum Version pip extra Notes
238+
======================================================================================================================================= ================== ================== =============================
239+
`scikits.odes <https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-scikits-odes-solver>`__ \- odes For scikits ODE & DAE solvers
240+
======================================================================================================================================= ================== ================== =============================
241241

242242
.. note::
243243

244-
Before running ``pip install "pybamm[odes]"``, make sure to install ``scikits.odes`` build-time requirements as described `here <https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-scikits-odes-solver>`_ .
244+
Before running ``pip install "pybamm[odes]"``, make sure to install ``scikits.odes`` build-time requirements as described `here <https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-scikits-odes-solver>`_ .
245245

246246
Full installation guide
247247
-----------------------
@@ -251,7 +251,7 @@ Installing a specific version? Installing from source? Check the advanced instal
251251
.. toctree::
252252
:maxdepth: 1
253253

254-
GNU-linux
254+
gnu-linux-mac
255255
windows
256256
windows-wsl
257257
install-from-source

docs/source/user_guide/installation/windows-wsl.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Get PyBaMM's Source Code
3737
5. Follow the Installation Steps
3838
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3939

40-
Follow the `installation instructions for PyBaMM on Linux <GNU-linux.html>`__.
40+
Follow the `installation instructions for PyBaMM on Linux <gnu-linux-mac.html>`__.
4141

4242
Using Visual Studio Code with the WSL
4343
---------------------------------------

pybamm/expression_tree/operations/evaluate_python.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class JaxCooMatrix:
4141
def __init__(self, row, col, data, shape):
4242
if not pybamm.have_jax(): # pragma: no cover
4343
raise ModuleNotFoundError(
44-
"Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-jaxsolver"
44+
"Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver"
4545
)
4646

4747
self.row = jax.numpy.array(row)
@@ -522,7 +522,7 @@ class EvaluatorJax:
522522
def __init__(self, symbol):
523523
if not pybamm.have_jax(): # pragma: no cover
524524
raise ModuleNotFoundError(
525-
"Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html#optional-jaxsolver"
525+
"Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver"
526526
)
527527

528528
constants, python_str = pybamm.to_python(symbol, debug=False, output_jax=True)

pybamm/install_odes.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99

1010
from pybamm.util import root_dir
1111

12+
if sys.platform == "win32":
13+
raise Exception("pybamm_install_odes is not supported on Windows.")
14+
15+
SUNDIALS_VERSION = "6.5.0"
16+
17+
# Build in parallel wherever possible
18+
os.environ["CMAKE_BUILD_PARALLEL_LEVEL"] = str(cpu_count())
19+
1220
try:
1321
# wget module is required to download SUNDIALS or SuiteSparse.
1422
import wget
@@ -37,19 +45,13 @@ def download_extract_library(url, directory):
3745
def install_sundials(download_dir, install_dir):
3846
# Download the SUNDIALS library and compile it.
3947
logger = logging.getLogger("scikits.odes setup")
40-
sundials_version = "6.5.0"
4148

4249
try:
4350
subprocess.run(["cmake", "--version"])
4451
except OSError:
4552
raise RuntimeError("CMake must be installed to build SUNDIALS.")
4653

47-
url = (
48-
"https://github.com/LLNL/"
49-
+ "sundials/releases/download/v{}/sundials-{}.tar.gz".format(
50-
sundials_version, sundials_version
51-
)
52-
)
54+
url = f"https://github.com/LLNL/sundials/releases/download/v{SUNDIALS_VERSION}/sundials-{SUNDIALS_VERSION}.tar.gz"
5355
logger.info("Downloading sundials")
5456
download_extract_library(url, download_dir)
5557

@@ -58,7 +60,7 @@ def install_sundials(download_dir, install_dir):
5860
"-DSUNDIALS_INDEX_SIZE=32",
5961
"-DBUILD_ARKODE:BOOL=OFF",
6062
"-DEXAMPLES_ENABLE:BOOL=OFF",
61-
"-DCMAKE_INSTALL_PREFIX=" + install_dir,
63+
f"-DCMAKE_INSTALL_PREFIX={install_dir}",
6264
]
6365

6466
# SUNDIALS are built within directory 'build_sundials' in the PyBaMM root
@@ -70,7 +72,7 @@ def install_sundials(download_dir, install_dir):
7072

7173
print("-" * 10, "Running CMake prepare", "-" * 40)
7274
subprocess.run(
73-
["cmake", f"../sundials-{sundials_version}", *cmake_args],
75+
["cmake", f"../sundials-{SUNDIALS_VERSION}", *cmake_args],
7476
cwd=build_directory,
7577
check=True,
7678
)
@@ -81,23 +83,40 @@ def install_sundials(download_dir, install_dir):
8183

8284

8385
def update_LD_LIBRARY_PATH(install_dir):
84-
# Look for current python virtual env and add export statement
85-
# for LD_LIBRARY_PATH in activate script. If no virtual env found,
86-
# then the current user's .bashrc file is modified instead.
86+
# Look for the current python virtual env and add an export statement
87+
# for LD_LIBRARY_PATH in the activate script. If no virtual env is found,
88+
# the current user's .bashrc file is modified instead.
8789

8890
export_statement = f"export LD_LIBRARY_PATH={install_dir}/lib:$LD_LIBRARY_PATH"
8991

92+
home_dir = os.environ.get("HOME")
93+
bashrc_path = os.path.join(home_dir, ".bashrc")
94+
zshrc_path = os.path.join(home_dir, ".zshrc")
9095
venv_path = os.environ.get("VIRTUAL_ENV")
96+
9197
if venv_path:
9298
script_path = os.path.join(venv_path, "bin/activate")
9399
else:
94-
script_path = os.path.join(os.environ.get("HOME"), ".bashrc")
100+
if os.path.exists(bashrc_path):
101+
script_path = os.path.join(os.environ.get("HOME"), ".bashrc")
102+
elif os.path.exists(zshrc_path):
103+
script_path = os.path.join(os.environ.get("HOME"), ".zshrc")
104+
elif os.path.exists(bashrc_path) and os.path.exists(zshrc_path):
105+
print(
106+
"Both .bashrc and .zshrc found in the home directory. Setting .bashrc as path"
107+
)
108+
script_path = os.path.join(os.environ.get("HOME"), ".bashrc")
109+
else:
110+
print("Neither .bashrc nor .zshrc found in the home directory.")
95111

96112
if os.getenv("LD_LIBRARY_PATH") and f"{install_dir}/lib" in os.getenv(
97113
"LD_LIBRARY_PATH"
98114
):
99115
print(f"{install_dir}/lib was found in LD_LIBRARY_PATH.")
100-
print("--> Not updating venv activate or .bashrc scripts")
116+
if os.path.exists(bashrc_path):
117+
print("--> Not updating venv activate or .bashrc scripts")
118+
if os.path.exists(zshrc_path):
119+
print("--> Not updating venv activate or .zshrc scripts")
101120
else:
102121
with open(script_path, "a+") as fh:
103122
# Just check that export statement is not already there.
@@ -140,7 +159,7 @@ def main(arguments=None):
140159
else os.path.join(pybamm_dir, args.install_dir)
141160
)
142161

143-
# Check is sundials is already installed
162+
# Check if sundials is already installed
144163
SUNDIALS_LIB_DIRS = [join(os.getenv("HOME"), ".local"), "/usr/local", "/usr"]
145164

146165
if args.sundials_libs:

0 commit comments

Comments
 (0)