Skip to content

Commit c37a0fa

Browse files
Sfonxuslayoo
andauthored
Add examples as PyMPDATA-MPI dependency, dynamic_advector option w/ stashes, fully JIT-able SWE code, interpolated indexers logic (for 1D & 2D), multiple advectees in solver, AnteStep class (#612)
Co-authored-by: Sylwester Arabas <[email protected]>
1 parent cfb7194 commit c37a0fa

File tree

19 files changed

+825
-248
lines changed

19 files changed

+825
-248
lines changed

.github/workflows/mpi.yml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
- if: steps.cache.outputs.cache-hit != 'true'
8989
run: |
9090
HDF5_MPI="ON" CC=mpicc pip install --no-binary=h5py h5py==3.13.0
91-
pip install -e MPI[tests]
91+
pip install -e .[tests] -e ./examples[tests] -e ./MPI[tests]
9292
- run: pip show numpy
9393
- id: cache-save
9494
if: steps.cache.outputs.cache-hit != 'true'
@@ -101,15 +101,18 @@ jobs:
101101
needs: [tests_setup]
102102
strategy:
103103
matrix:
104-
platform: [macos-15-intel, macos-14, ubuntu-latest]
104+
# Due to reported performance issues, runs on macos-15-intel are skipped
105+
# https://github.com/actions/runner-images/issues/12545
106+
# platform: [macos-15-intel, macos-14, ubuntu-latest]
107+
platform: [macos-14, ubuntu-latest]
105108
mpi: [ 'mpich', 'openmpi', 'intelmpi']
106109
python-version: ["3.10"]
107110
disable-jit: [1, 0]
108111
mpi-np: [1, 2, 3]
109112
exclude:
110113
# as of time of writing, mpi4py/setup-mpi does not support it
111-
- platform: macos-15-intel
112-
mpi: intelmpi
114+
# - platform: macos-15-intel
115+
# mpi: intelmpi
113116
- platform: macos-14
114117
mpi: intelmpi
115118

@@ -118,14 +121,14 @@ jobs:
118121
mpi: intelmpi
119122

120123
# https://github.com/Homebrew/homebrew-core/issues/26974
121-
- platform: macos-15-intel
122-
mpi: mpich
124+
# - platform: macos-15-intel
125+
# mpi: mpich
123126
- platform: macos-14
124127
mpi: mpich
125128

126129
# HDF5_MPI expects arm architecture with python 3.12 on macos
127-
- platform: macos-15-intel
128-
python-version: '3.12'
130+
# - platform: macos-15-intel
131+
# python-version: '3.12'
129132

130133
fail-fast: false
131134

MPI/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ build-backend = "setuptools.build_meta"
1414
name = "pympdata-mpi"
1515
description = "PyMPDATA + numba-mpi coupler sandbox"
1616
readme = "README.md"
17-
requires-python = ">=3.10"
17+
requires-python = ">=3.9"
1818
keywords = ["MPI", "MPDATA", "Numba", "PyMPDATA"]
1919
license = {text = "GPL-3.0"}
2020
classifiers = [
@@ -32,6 +32,7 @@ dependencies = [
3232
"numpy<1.25.0",
3333
"numba_mpi>=0.30",
3434
"PyMPDATA",
35+
"PyMPDATA-examples",
3536
"mpi4py==4.0.3",
3637
"h5py",
3738
]

PyMPDATA/impl/formulae_divide.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""Operation logic for dividing the field by
2+
a set divisor table and saving the result
3+
to a seperate field. Requires 'dynmaic_advector'
4+
option to be enabled.
5+
Scalar field inputs are named after dimensional
6+
components of the VectorField, not to be confused
7+
with internal enumerations on axis indexing"""
8+
9+
import numba
10+
import numpy as np
11+
12+
from .enumerations import INNER, MID3D, OUTER
13+
from .meta import META_HALO_VALID
14+
15+
16+
def make_divide_or_zero(options, traversals):
17+
"""returns njit-ted function for use with given traversals"""
18+
19+
n_dims = traversals.n_dims
20+
21+
@numba.njit(**options.jit_flags)
22+
# pylint: disable=too-many-arguments
23+
def divide_or_zero(
24+
out_outer_meta,
25+
out_outer_data,
26+
out_mid3d_meta,
27+
out_mid3d_data,
28+
out_inner_meta,
29+
out_inner_data,
30+
_,
31+
dividend_outer,
32+
__,
33+
dividend_mid3d,
34+
___,
35+
dividend_inner,
36+
____,
37+
divisor,
38+
time_step,
39+
grid_step,
40+
):
41+
eps = 1e-7
42+
for i in np.ndindex(out_inner_data.shape):
43+
if n_dims > 1:
44+
out_outer_data[i] = (
45+
dividend_outer[i] / divisor[i] * time_step / grid_step[OUTER]
46+
if divisor[i] > eps
47+
else 0
48+
)
49+
if n_dims > 2:
50+
out_mid3d_data[i] = (
51+
dividend_mid3d[i] / divisor[i] * time_step / grid_step[MID3D]
52+
if divisor[i] > eps
53+
else 0
54+
)
55+
out_inner_data[i] = (
56+
dividend_inner[i] / divisor[i] * time_step / grid_step[INNER]
57+
if divisor[i] > eps
58+
else 0
59+
)
60+
if n_dims > 1:
61+
out_outer_meta[META_HALO_VALID] = False
62+
if n_dims > 2:
63+
out_mid3d_meta[META_HALO_VALID] = False
64+
out_inner_meta[META_HALO_VALID] = False
65+
66+
return divide_or_zero

PyMPDATA/impl/indexers.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pathlib import Path
88

99
import numba
10+
import numpy as np
1011

1112
from .enumerations import INNER, INVALID_INDEX, MID3D, OUTER
1213

@@ -31,6 +32,14 @@ def ats_1d(focus, arr, k, _=INVALID_INDEX, __=INVALID_INDEX):
3132
def atv_1d(focus, arrs, k, _=INVALID_INDEX, __=INVALID_INDEX):
3233
return arrs[INNER][focus[INNER] + int(k - 0.5)]
3334

35+
@staticmethod
36+
@numba.njit(**jit_flags)
37+
def ati_1d(focus, arrs, k, _=INVALID_INDEX, __=INVALID_INDEX):
38+
return (
39+
arrs[INNER][focus[INNER] + int(k - 0.5)]
40+
+ arrs[INNER][focus[INNER] + int(k + 0.5)]
41+
) / 2
42+
3443
@staticmethod
3544
@numba.njit(**jit_flags)
3645
def set(arr, _, __, k, value):
@@ -70,6 +79,28 @@ def atv_axis1(focus, arrs, k, i=0, _=INVALID_INDEX):
7079
dim, _ii, _kk = OUTER, int(i - 0.5), int(k)
7180
return arrs[dim][focus[OUTER] + _ii, focus[INNER] + _kk]
7281

82+
@staticmethod
83+
@numba.njit(**jit_flags)
84+
def ati_axis0(focus, arrs, i, k=0, _=INVALID_INDEX):
85+
if _is_integral(k):
86+
dim, _ii, _kk = OUTER, int(i - 0.5), int(k)
87+
return (
88+
arrs[dim][focus[OUTER] + _ii, focus[INNER] + _kk]
89+
+ arrs[dim][focus[OUTER] + _ii + 1, focus[INNER] + _kk]
90+
) / 2
91+
return np.nan
92+
93+
@staticmethod
94+
@numba.njit(**jit_flags)
95+
def ati_axis1(focus, arrs, k, i=0, _=INVALID_INDEX):
96+
if _is_integral(i):
97+
dim, _ii, _kk = INNER, int(i), int(k - 0.5)
98+
return (
99+
arrs[dim][focus[OUTER] + _ii, focus[INNER] + _kk]
100+
+ arrs[dim][focus[OUTER] + _ii, focus[INNER] + _kk + 1]
101+
) / 2
102+
return np.nan
103+
73104
@staticmethod
74105
@numba.njit(**jit_flags)
75106
def set(arr, i, _, k, value):
@@ -140,24 +171,31 @@ def get(arr, i, j, k):
140171
return arr[i, j, k]
141172

142173
Indexers = namedtuple( # pylint: disable=invalid-name
143-
Path(__file__).stem + "_Indexers", ("ats", "atv", "set", "get", "n_dims")
174+
Path(__file__).stem + "_Indexers", ("ats", "atv", "ati", "set", "get", "n_dims")
144175
)
145176

146177
indexers = (
147178
None,
148179
Indexers(
149-
(None, None, _1D.ats_1d), (None, None, _1D.atv_1d), _1D.set, _1D.get, 1
180+
(None, None, _1D.ats_1d),
181+
(None, None, _1D.atv_1d),
182+
(None, None, _1D.ati_1d),
183+
_1D.set,
184+
_1D.get,
185+
1,
150186
),
151187
Indexers(
152188
(_2D.ats_axis0, None, _2D.ats_axis1),
153189
(_2D.atv_axis0, None, _2D.atv_axis1),
190+
(_2D.ati_axis0, None, _2D.ati_axis1),
154191
_2D.set,
155192
_2D.get,
156193
2,
157194
),
158195
Indexers(
159196
(_3D.ats_axis0, _3D.ats_axis1, _3D.ats_axis2),
160197
(_3D.atv_axis0, _3D.atv_axis1, _3D.atv_axis2),
198+
(None, None, None),
161199
_3D.set,
162200
_3D.get,
163201
3,

PyMPDATA/options.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def __init__(
3232
DPDC: bool = False, # pylint: disable=invalid-name
3333
epsilon: float = 1e-15,
3434
non_zero_mu_coeff: bool = False,
35+
dynamic_advector: bool = False,
3536
dimensionally_split: bool = False,
3637
dtype: [np.float32, np.float64] = np.float64
3738
):
@@ -44,6 +45,7 @@ def __init__(
4445
"nonoscillatory": nonoscillatory,
4546
"third_order_terms": third_order_terms,
4647
"non_zero_mu_coeff": non_zero_mu_coeff,
48+
"dynamic_advector": dynamic_advector,
4749
"dimensionally_split": dimensionally_split,
4850
"dtype": dtype,
4951
"DPDC": DPDC,
@@ -131,6 +133,11 @@ def non_zero_mu_coeff(self) -> bool:
131133
"""flag enabling handling of Fickian diffusion term"""
132134
return self._values["non_zero_mu_coeff"]
133135

136+
@property
137+
def dynamic_advector(self) -> bool:
138+
"""flag enabling (todo desc)"""
139+
return self._values["dynamic_advector"]
140+
134141
@property
135142
def dimensionally_split(self) -> bool:
136143
"""flag disabling cross-dimensional terms in antidiffusive velocities"""

0 commit comments

Comments
 (0)