Skip to content

Commit 1500caa

Browse files
authored
Python: Add support for handling numpy vectors and JIT compilation with Numba (Closes #34) (#57)
Add support for handling numpy vectors as inputs/outputs and greater run time performance using Numba: when Numba is found, all functions are compiled using the Numba just in time (JIT) compiler.
1 parent f707fe6 commit 1500caa

File tree

3 files changed

+130
-49
lines changed

3 files changed

+130
-49
lines changed

.travis.yml

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,86 @@
11
dist: xenial
2-
sudo: required
32

4-
# TODO: blend Python and R together.
5-
6-
matrix:
3+
jobs:
74
include:
85
- language: python
9-
python: 3.6
10-
before_install:
11-
- pip freeze
12-
- pip uninstall numpy -y && pip install numpy==1.15.4 # FIXME: Temporary fix as f2py is buggy on numpy 1.16.0
13-
- sudo apt-get install gfortran
14-
- pip install Sphinx==2.4.* sphinx_bootstrap_theme sphinx-autodoc-typehints m2r cffi
15-
- sudo apt install snapd
16-
- sudo snap install dotnet-sdk --classic
17-
install:
18-
- sphinx-build docs/sphinx build/html
19-
- touch build/html/.nojekyll # https://help.github.com/articles/files-that-start-with-an-underscore-are-missing/
20-
- cd tests/js && npm install
21-
- cd $TRAVIS_BUILD_DIR
22-
script:
23-
# See https://stackoverflow.com/a/34140498 for why "python -m" is needed.
24-
- python3 -m pytest -v -s
25-
- cd tests/js && npm test
26-
- cd $TRAVIS_BUILD_DIR
27-
- cd src/c_sharp && dotnet-sdk.dotnet test
28-
- cd $TRAVIS_BUILD_DIR
6+
python: 3.8
7+
env:
8+
- USE_NUMBA=no
9+
addons:
10+
apt:
11+
packages:
12+
- gfortran
13+
14+
- language: python
15+
python: 3.8
16+
env:
17+
- USE_NUMBA=yes
18+
addons:
19+
apt:
20+
packages:
21+
- gfortran
22+
23+
- language: minimal
24+
addons:
25+
snaps:
26+
- name: dotnet-sdk
27+
env:
28+
- C_SHARP=yes
29+
2930
- language: r
30-
r: release
31-
before_install:
32-
- Rscript -e 'install.packages("devtools")'
33-
- cd $TRAVIS_BUILD_DIR/src/r
34-
- Rscript tools/deploy.R
35-
script:
36-
- R CMD build .
37-
- R CMD check --as-cran psychrolib*tar.gz
31+
32+
before_install:
33+
- |
34+
set -x
35+
if [[ "$TRAVIS_PYTHON_VERSION" ]]; then
36+
pip install cffi # Common to both
37+
if [[ "$USE_NUMBA" == "no" ]]; then
38+
pip install Sphinx==2.4.* sphinx_bootstrap_theme sphinx-autodoc-typehints m2r
39+
fi
40+
if [[ "$USE_NUMBA" == "yes" ]]; then
41+
pip install numba
42+
fi
43+
fi
44+
if [[ "$TRAVIS_R_VERSION" ]]; then
45+
Rscript -e 'install.packages("devtools")'
46+
cd "$TRAVIS_BUILD_DIR/src/r" || exit
47+
Rscript tools/deploy.R
48+
fi
49+
50+
install:
51+
- |
52+
set -x
53+
if [[ "$TRAVIS_PYTHON_VERSION" ]]; then
54+
sphinx-build docs/sphinx build/html
55+
touch build/html/.nojekyll # https://help.github.com/articles/files-that-start-with-an-underscore-are-missing/
56+
cd tests/js && npm install
57+
cd $TRAVIS_BUILD_DIR
58+
fi
59+
60+
script:
61+
- |
62+
set -x
63+
if [[ "$TRAVIS_PYTHON_VERSION" ]]; then
64+
cd $TRAVIS_BUILD_DIR
65+
# See https://stackoverflow.com/a/34140498 for why "python -m" is needed.
66+
python3 -m pytest -v -s
67+
# Javascript tests
68+
cd tests/js && npm test
69+
fi
70+
if [[ "$TRAVIS_R_VERSION" ]]; then
71+
R CMD build .
72+
R CMD check --as-cran psychrolib*tar.gz
73+
fi
74+
if [[ "$C_SHARP" ]]; then
75+
cd $TRAVIS_BUILD_DIR
76+
cd src/c_sharp && dotnet-sdk.dotnet test
77+
fi
3878
3979
deploy:
40-
provider: pages
41-
skip_cleanup: true
42-
github_token: $GITHUB_TOKEN
43-
local_dir: build/html
44-
on:
45-
branch: master
46-
condition: $TRAVIS_PYTHON_VERSION == 3.6
80+
provider: pages
81+
skip_cleanup: true
82+
github_token: $GITHUB_TOKEN
83+
local_dir: build/html
84+
on:
85+
branch: master
86+
condition: $USE_NUMBA == "no"

README.md

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,46 @@
1-
# <img src="assets/psychrolib_logo.svg" alt="PsychroLib Logo" height="40" width="40"> PsychroLib [![PyPI](https://img.shields.io/pypi/v/psychrolib)](https://pypi.org/project/PsychroLib) [![NuGet](https://img.shields.io/nuget/v/PsychroLib.svg?maxAge=600)](https://www.nuget.org/packages/PsychroLib) [![CRAN](http://www.r-pkg.org/badges/version/psychrolib)](https://cran.r-project.org/package=psychrolib)
1+
<div align="center">
2+
<img src="assets/psychrolib_logo.svg" alt="PsychroLib Logo" height="80" width="80">
23

4+
<!-- omit in toc -->
5+
# PsychroLib
36

4-
|CI and Tests | Paper DOI | Software DOI |
5-
|---|---|------|
6-
[![Build Status](https://travis-ci.com/psychrometrics/psychrolib.svg?branch=master)](https://travis-ci.com/psychrometrics/psychrolib) | [![DOI](https://joss.theoj.org/papers/10.21105/joss.01137/status.svg)](https://doi.org/10.21105/joss.01137) | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.2537945.svg)](https://doi.org/10.5281/zenodo.2537945)|
7+
[![PyPI](https://img.shields.io/pypi/v/psychrolib)](https://pypi.org/project/PsychroLib) [![NuGet](https://img.shields.io/nuget/v/PsychroLib.svg?maxAge=600)](https://www.nuget.org/packages/PsychroLib) [![CRAN](https://www.r-pkg.org/badges/version/psychrolib)](https://cran.r-project.org/package=psychrolib) [![Build Status](https://travis-ci.com/psychrometrics/psychrolib.svg?branch=master)](https://travis-ci.com/psychrometrics/psychrolib) [![DOI](https://joss.theoj.org/papers/10.21105/joss.01137/status.svg)](https://doi.org/10.21105/joss.01137) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.2537945.svg)](https://doi.org/10.5281/zenodo.2537945)
78

8-
PsychroLib is a library of functions to enable the calculation of psychrometric properties of moist and dry air. Versions of PsychroLib are available for Python, C, C#, Fortran, R, JavaScript, Microsoft Excel Visual Basic for Applications (VBA). The library works in both metric (SI) and imperial (IP) systems of units. For a general overview and a list of currently available functions, please see the [overview page](docs/overview.md).
9+
[Overview](#overview) | [Documentation](#documentation) | [Installation](#installation) | [How to cite](#how-to-cite) | [Contributing](#contributing) | [Development](#development) | [Copyright and license](#copyright-and-license) | [Acknowledgements](#acknowledgements)
10+
11+
</div>
12+
13+
14+
## Overview
15+
16+
PsychroLib is a software library to enable the calculation of psychrometric properties of moist and dry air. Versions of PsychroLib are available for Python, C, C#, Fortran, R, JavaScript, Microsoft Excel Visual Basic for Applications (VBA). PsychroLib works in both metric (SI) and imperial (IP) systems of units. For a general overview and a list of currently available functions, please see the [overview page](docs/overview.md).
917

1018

1119
## Documentation
1220

13-
The API documentation is available [here](https://psychrometrics.github.io/psychrolib/api_docs.html). Please note that although the API describes the Python version of the library, the API is common across all the supported language implementations. In R please note that (1) constants, like `ZERO_FAHRENHEIT_AS_RANKINE` are not exported (i.e. not directly accessible to users), (2) functions accept a vector, not a scalar (3) bulk calculations, like `CalcPsychrometricsFromRelHum` return a list.
21+
Please see the [Python API documentation](https://psychrometrics.github.io/psychrolib/api_docs.html) for the common API across all the supported language implementations. In Python, array support and improved runtime performance can be optionally enabled by installing [Numba](https://numba.pydata.org/). In R (1) constants, like `ZERO_FAHRENHEIT_AS_RANKINE` are not exported (i.e. not directly accessible to users), (2) functions accept a vector, not a scalar (3) bulk calculations, like `CalcPsychrometricsFromRelHum` return a list.
1422

1523
Examples on how to use PsychroLib in all the supported languages are described in [this guide](docs/examples.md).
1624

1725

18-
## Installing
26+
## Installation
1927

20-
- Python: from the [Python Package Index (PyPI)](https://pypi.org/project/PsychroLib/).
28+
- Python: from the [Python Package Index (PyPI)](https://pypi.org/project/PsychroLib/). [Numba](https://numba.pydata.org/) can be optionally installed to enable array support and faster runtime performance.
2129
- C# (.NET): from the [NuGet package](https://www.nuget.org/packages/PsychroLib/) manager or clone the repository, and bundle according to your requirements.
2230
- C, Fortran and JavaScript: clone the repository, and bundle according to your requirements.
2331
- VBA/Excel: download the ready-made spreadsheets from the [release tab](https://github.com/psychrometrics/psychrolib/releases).
2432
- R: from the [Comprehensive R Archive Network (CRAN)](https://cran.r-project.org/package=psychrolib).
2533

2634

27-
## Citing
35+
## How to cite
36+
37+
When using PsychroLib, please cite the software summary paper and software version using the following Digital Object Identifiers (DOIs) to [generate citations in your preferred style](https://citation.crosscite.org/):
38+
39+
| Software summary paper | Software version* |
40+
| ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
41+
| [![DOI](https://joss.theoj.org/papers/10.21105/joss.01137/status.svg)](https://doi.org/10.21105/joss.01137) | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.2537945.svg)](https://doi.org/10.5281/zenodo.2537945) |
2842

29-
If you are using PsychroLib, please cite the the summary paper (https://doi.org/10.21105/joss.01137) *together* with the specific version of PsychroLib you are using (see [list on Zenodo](https://doi.org/10.5281/zenodo.2537945) for all available versions).
43+
*please make sure to cite the same version you are using with the correct DOI. For a list of all available versions see see [more on Zenodo]((https://doi.org/10.5281/zenodo.2537945)).
3044

3145

3246
## Contributing

src/python/psychrolib.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,13 @@ def SetUnitSystem(Units: UnitSystem) -> None:
172172
else:
173173
PSYCHROLIB_TOLERANCE = 0.001
174174

175+
if has_numba:
176+
# Need to recompile functions when the system of units is changed as Numba considers these global variables compile-time constants.
177+
# See https://numba.pydata.org/numba-doc/dev/user/faq.html#numba-doesn-t-seem-to-care-when-i-modify-a-global-variable
178+
globals()['isIP'] = njit(isIP.py_func)
179+
for func in func_list:
180+
globals()[func[0]] = vectorize(func[1])
181+
175182
def GetUnitSystem() -> Optional[UnitSystem]:
176183
"""
177184
Return system of units in use.
@@ -1459,3 +1466,23 @@ def CalcPsychrometricsFromRelHum(TDryBulb: float, RelHum: float, Pressure: float
14591466
MoistAirVolume = GetMoistAirVolume(TDryBulb, HumRatio, Pressure)
14601467
DegreeOfSaturation = GetDegreeOfSaturation(TDryBulb, HumRatio, Pressure)
14611468
return HumRatio, TWetBulb, TDewPoint, VapPres, MoistAirEnthalpy, MoistAirVolume, DegreeOfSaturation
1469+
1470+
1471+
# This section provides support for vectorization through the use of the Numba library (http://numba.pydata.org/)
1472+
# If Numba is not installed, the library just works with scalars and vectorization is simply not supported
1473+
try:
1474+
from inspect import isfunction
1475+
from numba import vectorize, njit
1476+
1477+
has_numba = True
1478+
# Needs to compile as used in vectorized functions below.
1479+
isIP = njit(isIP)
1480+
# Vectorise all 'core' functions.
1481+
# Utility function are excluded as they are just wrappers.
1482+
func_list = []
1483+
for func in list(globals().items()):
1484+
if isfunction(func[1]) and func[0].startswith(('Get', 'dLnPws_')) and func != 'GetUnitSystem':
1485+
globals()[func[0]] = vectorize(func[1])
1486+
func_list.append(func)
1487+
except ImportError:
1488+
has_numba = False

0 commit comments

Comments
 (0)