Skip to content

Commit ffda176

Browse files
committed
Merge branch 'numba-optimized-components' of https://github.com/CliMT/climt into numba-optimized-components
2 parents 6b58f90 + 39ae471 commit ffda176

14 files changed

Lines changed: 678 additions & 448 deletions
Lines changed: 66 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,77 @@
11
name: Publish in GitHub Package Registry
22

3-
on:
4-
release:
5-
types: [published]
3+
on:
4+
release:
5+
types: [published]
66

77
jobs:
8-
build_wheels:
9-
name: Build wheels on ${{ matrix.os }}
10-
runs-on: ${{ matrix.os }}
11-
strategy:
12-
matrix:
13-
os: [ubuntu-latest, macOS-latest]
14-
#[ubuntu-20.04,macOS-11]
15-
#, windows-2019, macOS-10.15]
8+
build_wheels:
9+
name: Build wheels on ${{ matrix.os }}
10+
runs-on: ${{ matrix.os }}
11+
strategy:
12+
matrix:
13+
os: [ubuntu-latest, macOS-latest]
14+
#[ubuntu-20.04,macOS-11]
15+
#, windows-2019, macOS-10.15]
1616

17-
steps:
18-
- uses: actions/checkout@v4
17+
steps:
18+
- uses: actions/checkout@v4
1919

20-
# Used to host cibuildwheel
21-
- uses: actions/setup-python@v5
20+
# Used to host cibuildwheel
21+
- uses: actions/setup-python@v5
2222

23-
- name: Set up QEMU
24-
if: runner.os == 'Linux'
25-
uses: docker/setup-qemu-action@v3
26-
with:
27-
platforms: all
23+
- name: Set up QEMU
24+
if: runner.os == 'Linux'
25+
uses: docker/setup-qemu-action@v3
26+
with:
27+
platforms: all
2828

29-
- name: Install cibuildwheel
30-
run: python -m pip install cibuildwheel==2.22.1
29+
- name: Install cibuildwheel
30+
run: python -m pip install cibuildwheel==3.3.1
3131

32-
- name: Build on Linux
33-
env:
34-
CIBW_BUILD: cp39-* cp310-* cp311-* cp312-*
35-
CIBW_SKIP: "*-musllinux_*"
36-
CIBW_ARCHS_LINUX: "x86_64 aarch64"
37-
CIBW_ENVIRONMENT: "CC=gcc FC=gfortran CLIMT_ARCH=Linux"
38-
if: ${{ runner.os == 'Linux' }}
39-
run: python -m cibuildwheel --output-dir dist
40-
41-
- name: Build on macOS
42-
env:
43-
CIBW_BUILD: cp39-* cp310-* cp311-* cp312-*
44-
CIBW_ARCHS_MACOS: "arm64"
45-
CIBW_ENVIRONMENT: "CLIMT_ARCH=Darwin"
46-
if: ${{ runner.os == 'macOS' }}
47-
run: python -m cibuildwheel --output-dir dist
32+
- name: Build on Linux
33+
env:
34+
CIBW_BUILD: cp39-* cp310-* cp311-* cp312-*
35+
CIBW_SKIP: "*-musllinux_*"
36+
CIBW_ARCHS_LINUX: "x86_64"
37+
CIBW_ENVIRONMENT: "CC=gcc FC=gfortran CLIMT_ARCH=Linux"
38+
if: ${{ runner.os == 'Linux' }}
39+
run: python -m cibuildwheel --output-dir dist
4840

49-
- name: Store the distribution packages
50-
uses: actions/upload-artifact@v4
51-
with:
52-
name: python-package-distributions
53-
path: dist/
54-
publish-to-pypi:
55-
name: Publishing to PyPI
56-
needs:
57-
- build_wheels
58-
runs-on: ubuntu-latest
59-
environment:
60-
name: pypi
61-
url: https://pypi.org/p/climt # Replace <package-name> with your PyPI project name
62-
permissions:
63-
id-token: write # IMPORTANT: mandatory for trusted publishing
64-
steps:
65-
- name: Download all the dists
66-
uses: actions/download-artifact@v4
67-
with:
68-
name: python-package-distributions
69-
path: dist/
70-
- name: Publish wheels to PyPI
71-
uses: pypa/gh-action-pypi-publish@release/v1
72-
# # - name: upload wheels
73-
# # env:
74-
# # TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
75-
# # TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
76-
# # run: twine upload wheelhouse/* --verbose
41+
- name: Build on macOS
42+
env:
43+
CIBW_BUILD: cp39-* cp310-* cp311-* cp312-*
44+
CIBW_ARCHS_MACOS: "arm64"
45+
CIBW_ENVIRONMENT: "CLIMT_ARCH=Darwin MACOSX_DEPLOYMENT_TARGET=15.0"
46+
if: ${{ runner.os == 'macOS' }}
47+
run: python -m cibuildwheel --output-dir dist
7748

78-
49+
- name: Store the distribution packages
50+
uses: actions/upload-artifact@v4
51+
with:
52+
name: python-package-distributions-${{ matrix.os }}
53+
path: dist/
54+
publish-to-pypi:
55+
name: Publishing to PyPI
56+
needs:
57+
- build_wheels
58+
runs-on: ubuntu-latest
59+
environment:
60+
name: pypi
61+
url: https://pypi.org/p/climt # Replace <package-name> with your PyPI project name
62+
permissions:
63+
id-token: write # IMPORTANT: mandatory for trusted publishing
64+
steps:
65+
- name: Download all the dists
66+
uses: actions/download-artifact@v4
67+
with:
68+
pattern: python-package-distributions-*
69+
merge-multiple: true
70+
path: dist/
71+
- name: Publish wheels to PyPI
72+
uses: pypa/gh-action-pypi-publish@release/v1
73+
# # - name: upload wheels
74+
# # env:
75+
# # TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
76+
# # TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
77+
# # run: twine upload wheelhouse/* --verbose

climt/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,4 @@
7171
BucketHydrology,
7272
)
7373

74-
__version__ = "0.18.3"
74+
__version__ = "0.18.5"

climt/_core/initialization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from datetime import datetime
23

34
import numpy as np
@@ -9,7 +10,6 @@
910
get_constant,
1011
set_constant,
1112
)
12-
import sys
1313

1414
if sys.version_info < (3, 9):
1515
import importlib_resources

climt/_core/unyt_backend.py

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,33 @@ class UnytStateContainer:
9393
dims (tuple of str): The names of the dimensions.
9494
"""
9595

96-
def __init__(self, data, dims):
97-
if not isinstance(data, (unyt.unyt_array, np.ndarray)):
96+
def __init__(self, data, dims=None, attrs=None):
97+
if not isinstance(
98+
data, (unyt.unyt_array, np.ndarray, float, int, np.floating, np.integer)
99+
):
98100
# Ideally strict, but helpful to be flexible if easy.
99101
# For now, strict to match design.
100102
raise TypeError(
101103
f"Data must be a unyt.unyt_array or numpy.ndarray, got {type(data)}"
102104
)
105+
106+
if (
107+
attrs is not None
108+
and "units" in attrs
109+
and not isinstance(data, unyt.unyt_array)
110+
):
111+
try:
112+
sanitized_units = attrs["units"].replace("^", "**").replace(" ", "*")
113+
data = unyt.unyt_array(data, sanitized_units)
114+
except Exception:
115+
pass
116+
103117
self.data = data
104-
self.dims = tuple(dims)
118+
self.dims = tuple(dims) if dims is not None else ()
119+
120+
def rename(self, name_dict):
121+
new_dims = [name_dict.get(d, d) for d in self.dims]
122+
return UnytStateContainer(self.data, new_dims)
105123

106124
def __repr__(self):
107125
return f"UnytStateContainer(data={self.data}, dims={self.dims})"
@@ -131,6 +149,68 @@ def attrs(self):
131149
return {"units": str(self.data.units)}
132150
return {}
133151

152+
class _LocIndexer:
153+
def __init__(self, container):
154+
self.container = container
155+
156+
def __getitem__(self, key):
157+
if isinstance(key, dict):
158+
slices = []
159+
for dim in self.container.dims:
160+
if dim in key:
161+
slices.append(key[dim])
162+
else:
163+
slices.append(slice(None))
164+
return self.container[tuple(slices)]
165+
return self.container[key]
166+
167+
def __setitem__(self, key, value):
168+
if isinstance(key, dict):
169+
slices = []
170+
for dim in self.container.dims:
171+
if dim in key:
172+
slices.append(key[dim])
173+
else:
174+
slices.append(slice(None))
175+
self.container[tuple(slices)] = value
176+
else:
177+
self.container[key] = value
178+
179+
@property
180+
def loc(self):
181+
return self._LocIndexer(self)
182+
183+
def transpose(self, *dims):
184+
if len(dims) == 1 and isinstance(dims[0], (tuple, list)):
185+
dims = dims[0]
186+
# map dim names to axis indices
187+
perm = [self.dims.index(dim) for dim in dims]
188+
return UnytStateContainer(self.data.transpose(perm), dims)
189+
190+
def __getitem__(self, key):
191+
sliced_data = self.data[key]
192+
if isinstance(sliced_data, (unyt.unyt_array, np.ndarray)):
193+
if sliced_data.ndim == len(self.dims):
194+
return UnytStateContainer(sliced_data, self.dims)
195+
else:
196+
# Provide dummy dimensions or just truncate if we cannot infer dropped dimension easily
197+
# Truncate to match ndim for now
198+
return UnytStateContainer(sliced_data, self.dims[: sliced_data.ndim])
199+
return sliced_data
200+
201+
def __eq__(self, other):
202+
if isinstance(other, UnytStateContainer):
203+
return self.data == other.data
204+
return self.data == other
205+
206+
def __setitem__(self, key, value):
207+
if isinstance(value, UnytStateContainer):
208+
self.data[key] = value.data
209+
elif isinstance(value, unyt.unyt_array) and hasattr(self.data, "units"):
210+
self.data[key] = value.to(self.data.units)
211+
else:
212+
self.data[key] = value
213+
134214
def to_units(self, units):
135215
if not isinstance(self.data, unyt.unyt_array):
136216
return self

climt/_core/util.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import functools
22

3-
# from .backend import jit_compile
43
import numpy as np
5-
from sympl import DataArray
4+
from sympl import DataArray # pyright: ignore[reportMissingImports]
65

76

87
def ensure_contiguous_state(func):

docs/component_manual.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ Component Manual
33

44
.. toctree::
55
rrtmg_clouds
6+
emanuel_convection

rad_conv_eq_unyt.nc

-122 KB
Binary file not shown.

requirements_dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ numpy>=1.16.0
1919
cython>=0.25
2020
ipython>=5.3.0
2121
coveralls
22-
sympl==0.5.0
22+
sympl>=0.5.0

setup.cfg

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[bumpversion]
2-
current_version = 0.18.3
2+
current_version = 0.18.5
33
commit = True
44
tag = False
55

66
[bumpversion:file:setup.py]
7-
search = version='{current_version}'
8-
replace = version='{new_version}'
7+
search = version="{current_version}"
8+
replace = version="{new_version}"
99

1010
[bumpversion:file:climt/__init__.py]
1111
search = __version__ = "{current_version}"

0 commit comments

Comments
 (0)