Skip to content

Commit 2fb34d5

Browse files
authored
move PyMPDATA-examples to examples; simplify dependency logic; execute notebooks from devops_tests (#400)
1 parent 1863ec2 commit 2fb34d5

File tree

82 files changed

+6618
-38
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+6618
-38
lines changed

.binder/postBuild

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
# mimicking what happens on Colab: packages are fetched from PyPI, only notebooks from the repo
4+
5+
set -e
6+
shopt -s extglob
7+
rm -rfv !("examples")

.binder/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PyMPDATA-examples

.github/workflows/pdoc_index_workaround.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
modules = [
1111
import_module(module, reload=True)
12-
for module in ('PyMPDATA', 'PyMPDATA-examples/PyMPDATA_examples')
12+
for module in ('PyMPDATA', 'examples/PyMPDATA_examples')
1313
]
1414

1515
with open('html/index.html', 'w', encoding='utf-8') as index:

.github/workflows/tests+pypi.yml

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
precommit:
1919
strategy:
2020
matrix:
21-
package-dir: [".", "PyMPDATA-examples"]
21+
package-dir: [".", "examples"]
2222
runs-on: ubuntu-latest
2323
steps:
2424
- uses: actions/checkout@v2
@@ -46,8 +46,7 @@ jobs:
4646
python-version: 3.9
4747
- name: Generate coverage report
4848
run: |
49-
pip install -e .[tests]
50-
pip install -e ./PyMPDATA-examples
49+
pip install -e .[tests] ./examples
5150
pip install pytest-cov
5251
pytest --durations=10 -We tests/unit_tests --cov-report=xml --cov=PyMPDATA
5352
- name: Upload coverage to Codecov
@@ -71,22 +70,17 @@ jobs:
7170
run: |
7271
python -m pip install --upgrade pip
7372
pip install pylint nbqa pdoc3 # (pdoc3 for checking the .github/workflows/pdoc_index_workaround.py)
74-
pip install -e ./PyMPDATA-examples[tests]
75-
pip install -e .[tests]
73+
pip install -e .[tests] ./examples[tests]
7674
- run: |
77-
pylint --max-module-lines=500 --disable=fixme $(git ls-files '*.py')
75+
pylint --max-module-lines=500 --disable=fixme $(git ls-files '*.py' | grep -v ^examples)
7876
- run: |
7977
# TODO #299
80-
cd PyMPDATA-examples
8178
pylint --disable=fixme --max-module-lines=200 \
82-
--disable=too-many-locals,too-many-branches,duplicate-code,invalid-name,missing-function-docstring,missing-module-docstring,too-many-arguments,missing-class-docstring,too-many-instance-attributes $(git ls-files '*.py')
83-
cd ..
79+
--disable=too-many-locals,too-many-branches,duplicate-code,invalid-name,missing-function-docstring,missing-module-docstring,too-many-arguments,missing-class-docstring,too-many-instance-attributes $(git ls-files '*.py' | grep ^examples)
8480
- run: |
8581
# TODO #299
86-
cd PyMPDATA-examples
87-
nbqa pylint --disable=fixme,trailing-whitespace,wrong-import-position,ungrouped-imports \
82+
nbqa pylint --disable=fixme,trailing-whitespace,wrong-import-position,wrong-import-order,ungrouped-imports \
8883
--disable=duplicate-code,invalid-name,missing-module-docstring,line-too-long,missing-function-docstring,redefined-outer-name,too-many-arguments,no-member,too-many-locals,cell-var-from-loop,missing-class-docstring $(git ls-files '*.ipynb')
89-
cd ..
9084
pdoc:
9185
strategy:
9286
matrix:
@@ -100,11 +94,12 @@ jobs:
10094
- uses: actions/setup-python@v2
10195
with:
10296
python-version: 3.9
103-
- run: |
97+
- env:
98+
JUPYTER_PLATFORM_DIRS: 1
99+
run: |
104100
pip3 install pdoc3
105-
pip install -e .
106-
pip install -e . PyMPDATA-examples
107-
python -We -m pdoc --html PyMPDATA PyMPDATA-examples/PyMPDATA_examples
101+
pip install -e . ./examples
102+
python -We -m pdoc --html PyMPDATA examples/PyMPDATA_examples
108103
python -We .github/workflows/pdoc_index_workaround.py
109104
- if: ${{ github.ref == 'refs/heads/main' && matrix.platform == 'ubuntu-latest' }}
110105
uses: JamesIves/github-pages-deploy-action@4.1.1
@@ -145,8 +140,7 @@ jobs:
145140
- run: |
146141
python -We -c "import PyMPDATA"
147142
- run: |
148-
pip install -e ./PyMPDATA-examples
149-
pip install -e .[tests]
143+
pip install -e .[tests] ./examples
150144
# https://github.com/numba/numba/issues/6350#issuecomment-728174860
151145
- if: startsWith(matrix.platform, 'ubuntu-')
152146
run: echo NUMBA_THREADING_LAYER=omp >> $GITHUB_ENV
@@ -161,7 +155,7 @@ jobs:
161155
strategy:
162156
matrix:
163157
platform: [ubuntu-latest, macos-latest, windows-latest]
164-
python-version: ["3.7", "3.10"]
158+
python-version: ["3.8", "3.10"]
165159
fail-fast: false
166160
runs-on: ${{ matrix.platform }}
167161
steps:
@@ -172,12 +166,8 @@ jobs:
172166
- uses: actions/setup-python@v1
173167
with:
174168
python-version: ${{ matrix.python-version }}
175-
- run: |
176-
pip install -e ./PyMPDATA-examples[tests]
177-
- run: |
178-
python -We -c "import PyMPDATA_examples"
179-
- run: |
180-
pip install -e .[tests]
169+
- run: pip install -e .[tests] ./examples
170+
- run: pip install -r tests/devops_tests/requirements.txt
181171
- if: matrix.platform == 'ubuntu-latest'
182172
run: |
183173
sudo apt-get install libblitz0-dev libboost-thread-dev libboost-date-time-dev libboost-system-dev libboost-iostreams-dev libboost-timer-dev libboost-filesystem-dev
@@ -194,9 +184,7 @@ jobs:
194184
- if: matrix.platform == 'ubuntu-latest'
195185
run: echo NUMBA_THREADING_LAYER=omp >> $GITHUB_ENV
196186

197-
- env:
198-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
199-
run: pytest --durations=10 -p no:unraisableexception -We PyMPDATA-examples
187+
- run: pytest --durations=10 -p no:unraisableexception -We tests/devops_tests/test_run_notebooks.py
200188

201189
devops:
202190
runs-on: ubuntu-latest
@@ -206,14 +194,15 @@ jobs:
206194
submodules: recursive
207195
fetch-depth: 0 # https://github.com/pypa/setuptools_scm/issues/480
208196
- run: pip install -r tests/devops_tests/requirements.txt
197+
- run: pip install -e . ./examples
209198
- env:
210199
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
211-
run: pytest --durations=10 -v -s -We -p no:unraisableexception tests/devops_tests
200+
run: pytest --durations=10 -v -s -We -p no:unraisableexception -k "not run_notebooks" tests/devops_tests
212201

213202
dist:
214203
strategy:
215204
matrix:
216-
package-dir: [".", "PyMPDATA-examples"]
205+
package-dir: [".", "examples"]
217206
fail-fast: false
218207
runs-on: ubuntu-latest
219208
needs: [tests, examples, devops]

.gitmodules

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
[submodule "PyMPDATA-examples"]
2-
path = PyMPDATA-examples
3-
url = git@github.com:open-atmos/PyMPDATA-examples.git
4-
shallow = true
51
[submodule "tests/devops_tests"]
62
path = tests/devops_tests
7-
url = git@github.com:open-atmos/devops_tests.git
3+
url = https://github.com/open-atmos/devops_tests
4+
shallow = true

PyMPDATA-examples

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import numpy as np
2+
import PyMPDATA_examples.Arabas_and_Farhat_2020.Black_Scholes_1973 as BS
3+
4+
5+
def _phi(
6+
S: [np.ndarray, float],
7+
gamma: float,
8+
H: float,
9+
I: float,
10+
r: float,
11+
b: float,
12+
var: float,
13+
T: float,
14+
):
15+
lmbd = (-r + gamma * b + 0.5 * gamma * (gamma - 1) * var) * T
16+
d = -(np.log(S / H) + (b + (gamma - 0.5) * var) * T) / np.sqrt(var * T)
17+
kappa = 2 * b / var + (2 * gamma - 1)
18+
return (
19+
np.exp(lmbd)
20+
* np.power(S, gamma)
21+
* (
22+
BS.N(d)
23+
- pow((I / S), kappa) * BS.N(d - 2 * np.log(I / S) / np.sqrt(var * T))
24+
)
25+
)
26+
27+
28+
def c_amer(
29+
S: [np.ndarray, float],
30+
K: [float, np.ndarray],
31+
T: float,
32+
r: float,
33+
b: float,
34+
sgma: float,
35+
):
36+
if b >= r:
37+
return BS.c_euro(S, K=K, T=T, r=r, b=b, sgma=sgma)
38+
39+
var = sgma * sgma
40+
beta = (0.5 - b / var) + np.sqrt(pow((b / var - 0.5), 2) + 2 * r / var)
41+
BInf = beta / (beta - 1) * K
42+
B0 = np.maximum(K, r / (r - b) * K)
43+
ht = -(b * T + 2 * sgma * np.sqrt(T)) * B0 / (BInf - B0)
44+
I = B0 + (BInf - B0) * (1 - np.exp(ht))
45+
alpha = (I - K) * pow(I, -beta)
46+
47+
return np.where(
48+
S >= I,
49+
S - K,
50+
alpha * np.power(S, beta)
51+
+ (
52+
-alpha * _phi(S, gamma=beta, H=I, I=I, r=r, b=b, var=var, T=T)
53+
+ _phi(S, gamma=1, H=I, I=I, r=r, b=b, var=var, T=T)
54+
- _phi(S, gamma=1, H=K, I=I, r=r, b=b, var=var, T=T)
55+
- K * _phi(S, gamma=0, H=I, I=I, r=r, b=b, var=var, T=T)
56+
+ K * _phi(S, gamma=0, H=K, I=I, r=r, b=b, var=var, T=T)
57+
),
58+
)
59+
60+
61+
def p_amer(S: [np.ndarray, float], K: float, T: float, r: float, b: float, sgma: float):
62+
return c_amer(K, K=S, T=T, r=r - b, b=-b, sgma=sgma)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import numpy as np
2+
from scipy.special import erf # pylint: disable=no-name-in-module
3+
4+
5+
def N(x: float):
6+
return (1 + erf(x / np.sqrt(2))) / 2
7+
8+
9+
def c_euro(S: np.ndarray, K: float, T: float, r: float, b: float, sgma: float):
10+
d1 = (np.log(S / K) + (b + sgma * sgma / 2) * T) / sgma / np.sqrt(T)
11+
d2 = d1 - sgma * np.sqrt(T)
12+
return S * np.exp(b - r) * N(d1) - K * np.exp(-r * T) * N(d2)
13+
14+
15+
def p_euro(S: np.ndarray, K: float, T: float, r: float, b: float, sgma: float):
16+
d1 = (np.log(S / K) + (b + sgma * sgma / 2) * T) / sgma / np.sqrt(T)
17+
d2 = d1 - sgma * np.sqrt(T)
18+
return K * np.exp(-r * T) * N(-d2) - S * np.exp((b - r) * T) * N(-d1)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .simulation import Simulation
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import numpy as np
2+
from joblib import Parallel, delayed, parallel_backend
3+
from PyMPDATA_examples.Arabas_and_Farhat_2020.setup1_european_corridor import Settings
4+
from PyMPDATA_examples.Arabas_and_Farhat_2020.simulation import Simulation
5+
from PyMPDATA_examples.utils.error_norms import L2
6+
7+
8+
def compute(simulation):
9+
output = []
10+
for n_iters in (1, 2):
11+
simulation.run(n_iters)
12+
output.append(
13+
{
14+
"n_iters": n_iters,
15+
"log2_C": np.log2(simulation.C),
16+
"log2_C_opt": np.log2(simulation.settings.C_opt),
17+
"log2_l2": np.log2(simulation.l2),
18+
"log2_l2_opt": np.log2(simulation.settings.l2_opt),
19+
"err2": error_L2_norm(
20+
simulation.solvers,
21+
simulation.settings,
22+
simulation.S,
23+
simulation.nt,
24+
n_iters,
25+
),
26+
}
27+
)
28+
return output
29+
30+
31+
def convergence_in_space(num=8):
32+
with parallel_backend("threading", n_jobs=-2):
33+
data = Parallel(verbose=10)(
34+
delayed(compute)(
35+
Simulation(Settings(l2_opt=2**log2_l2_opt, C_opt=2**log2_C_opt))
36+
)
37+
for log2_C_opt in np.linspace(-9.5, -6, num=num)
38+
for log2_l2_opt in range(1, 4)
39+
)
40+
result = {}
41+
for pair in data:
42+
for datum in pair:
43+
label = f" $\\lambda^2\\approx2^{{{datum['log2_l2_opt']}}}$"
44+
key = ("upwind" + label, "MPDATA" + label)[datum["n_iters"] - 1]
45+
if key not in result:
46+
result[key] = ([], [])
47+
result[key][0].append(datum["log2_C"])
48+
result[key][1].append(datum["err2"])
49+
return result
50+
51+
52+
def convergence_in_time(num=13):
53+
with parallel_backend("threading", n_jobs=-2):
54+
data = Parallel(verbose=10)(
55+
delayed(compute)(
56+
Simulation(Settings(l2_opt=2**log2_l2_opt, C_opt=2**log2_C_opt))
57+
)
58+
for log2_C_opt in np.log2((0.01, 0.005, 0.0025))
59+
for log2_l2_opt in np.linspace(1.1, 3.5, num=num)
60+
)
61+
result = {}
62+
for pair in data:
63+
for datum in pair:
64+
label = f" $C\\approx{2**(datum['log2_C_opt']):.4f}$"
65+
key = ("upwind" + label, "MPDATA" + label)[datum["n_iters"] - 1]
66+
if key not in result:
67+
result[key] = ([], [])
68+
result[key][0].append(datum["log2_l2"])
69+
result[key][1].append(datum["err2"])
70+
return result
71+
72+
73+
def error_L2_norm(solvers, settings, S, nt, n_iters: int):
74+
numerical = solvers[n_iters].advectee.get()
75+
analytical = settings.analytical_solution(S)
76+
return L2(numerical, analytical, nt)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import numpy as np
2+
from joblib import Parallel, delayed, parallel_backend
3+
from PyMPDATA_examples.Arabas_and_Farhat_2020.analysis_figures_2_and_3 import (
4+
error_L2_norm,
5+
)
6+
from PyMPDATA_examples.Arabas_and_Farhat_2020.setup2_american_put import Settings
7+
from PyMPDATA_examples.Arabas_and_Farhat_2020.simulation import Simulation
8+
9+
10+
def compute_row(simulations):
11+
S0 = simulations[0].settings.S0
12+
T = simulations[0].settings.T
13+
for i in range(1, len(simulations)):
14+
assert simulations[i].settings.T == T
15+
assert simulations[i].settings.S0 == S0
16+
row = [T, S0]
17+
f = None
18+
for simulation in simulations:
19+
f = simulation.run(n_iters=2)
20+
row.append(
21+
error_L2_norm(
22+
simulation.solvers,
23+
simulation.settings,
24+
simulation.S,
25+
simulation.nt,
26+
n_iters=2,
27+
)
28+
)
29+
np.testing.assert_almost_equal(simulation.S[simulation.ix_match], S0)
30+
row.append(f[simulations[-1].ix_match])
31+
row.append(simulations[0].settings.analytical_solution(S0))
32+
row.append(simulations[0].settings.analytical_solution(S0, amer=False))
33+
return row
34+
35+
36+
def table_1_data():
37+
with parallel_backend("threading", n_jobs=-2):
38+
result = Parallel(verbose=10)(
39+
delayed(compute_row)(
40+
tuple(
41+
Simulation(Settings(T=T, C_opt=C_opt, S0=S0))
42+
for C_opt in (0.02, 0.01, 0.005)
43+
)
44+
)
45+
for T in (0.25, 0.5, 3)
46+
for S0 in (80, 90, 100, 110, 120)
47+
)
48+
return result
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
colors = ("purple", "teal", "turquoise")

0 commit comments

Comments
 (0)