Skip to content

Commit a6e0d1a

Browse files
authored
Merge pull request #70 from jrenaud90/dev0.6.1
0.6.1 - Improved RS Helper Performance
2 parents 8dc2e8f + c4d3ba3 commit a6e0d1a

File tree

13 files changed

+667
-275
lines changed

13 files changed

+667
-275
lines changed

Benchmarks & Performance/RadialSolver/RadialSolver - General Benchmarks and Performance.ipynb

Lines changed: 40 additions & 34 deletions
Large diffs are not rendered by default.
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"id": "b7617924-8ce7-4c34-bb98-1a0ab241c175",
7+
"metadata": {},
8+
"outputs": [
9+
{
10+
"name": "stdout",
11+
"output_type": "stream",
12+
"text": [
13+
"0.6.1\n"
14+
]
15+
}
16+
],
17+
"source": [
18+
"import TidalPy\n",
19+
"print(TidalPy.version)"
20+
]
21+
},
22+
{
23+
"cell_type": "code",
24+
"execution_count": 2,
25+
"id": "e5431759-b701-4895-8773-dd3c92e4cfd7",
26+
"metadata": {},
27+
"outputs": [],
28+
"source": [
29+
"import numpy as np\n",
30+
"from TidalPy.RadialSolver import build_rs_input_homogeneous_layers, build_rs_input_from_data\n",
31+
"from TidalPy.rheology import Maxwell, Elastic"
32+
]
33+
},
34+
{
35+
"cell_type": "markdown",
36+
"id": "f91165e3-cee0-4e6a-810a-35a006b9f521",
37+
"metadata": {},
38+
"source": [
39+
"## `build_rs_input_homogeneous_layers` Performance\n",
40+
"\n",
41+
"**v0.6.0:**\n",
42+
"\n",
43+
"slices_per_layer = 5; perform_checks=False; num_layers:\n",
44+
"- 1: 32.2us\n",
45+
"- 5: 33.4us\n",
46+
"- 10: 35.8us\n",
47+
"- 15: 37.7us\n",
48+
"- 20: 39.5us\n",
49+
"- 50: 52us\n",
50+
"- 100: 74us\n",
51+
"\n",
52+
"slices_per_layer = 5; perform_checks=True; num_layers:\n",
53+
"- 1: 32.5us\n",
54+
"- 5: 34.3us\n",
55+
"- 10: 35.7us\n",
56+
"- 15: 38.7us\n",
57+
"- 20: 40.6us\n",
58+
"- 50: 54us\n",
59+
"- 100: 75.3us\n",
60+
"\n",
61+
"slices_per_layer = 50; perform_checks=True; num_layers:\n",
62+
"- 1: 34.9us\n",
63+
"- 5: 47.8us\n",
64+
"- 10: 65.4us\n",
65+
"- 15: 82.0us\n",
66+
"- 20: 95.0us\n",
67+
"- 50: 188.0us\n",
68+
"- 100: 339.0us\n",
69+
"\n",
70+
"**v0.6.1:**\n",
71+
"slices_per_layer = 5; perform_checks=True; num_layers:\n",
72+
"- 1: 9.39 μs\n",
73+
"- 5: 10.8 μs\n",
74+
"- 10: 12.7 μs\n",
75+
"- 15: 14.6 μs\n",
76+
"- 20: 16.3 μs\n",
77+
"- 50: 26.9 μs\n",
78+
"- 100: 44.4 μs\n",
79+
"\n",
80+
"slices_per_layer = 50; perform_checks=True; num_layers:\n",
81+
"- 1: 11.8 μs\n",
82+
"- 5: 22.8 μs\n",
83+
"- 10: 36.5 μs\n",
84+
"- 15: 50.2 μs\n",
85+
"- 20: 64.9 μs\n",
86+
"- 50: 145 μs\n",
87+
"- 100: 280 μs"
88+
]
89+
},
90+
{
91+
"cell_type": "code",
92+
"execution_count": 4,
93+
"id": "c14d9a0b-1beb-453d-94cf-4d7aa3cec3c5",
94+
"metadata": {},
95+
"outputs": [
96+
{
97+
"name": "stdout",
98+
"output_type": "stream",
99+
"text": [
100+
"Working on #Layers = 1.\n",
101+
"9.39 μs ± 54.9 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n",
102+
"Working on #Layers = 5.\n",
103+
"10.8 μs ± 227 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n",
104+
"Working on #Layers = 10.\n",
105+
"12.7 μs ± 186 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n",
106+
"Working on #Layers = 15.\n",
107+
"14.6 μs ± 230 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n",
108+
"Working on #Layers = 20.\n",
109+
"16.3 μs ± 184 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n",
110+
"Working on #Layers = 50.\n",
111+
"26.9 μs ± 290 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
112+
"Working on #Layers = 100.\n",
113+
"44.4 μs ± 424 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n"
114+
]
115+
}
116+
],
117+
"source": [
118+
"slices_per_layer = 5\n",
119+
"perform_checks = True\n",
120+
"\n",
121+
"for num_layers in (1, 5, 10, 15, 20, 50, 100):\n",
122+
" planet_radius = 1.0e6\n",
123+
" forcing_frequency = 1.0e-4\n",
124+
" density_tuple = tuple([3000.0 for i in range(num_layers)])\n",
125+
" static_bulk_modulus_tuple = tuple([1.0e10 for i in range(num_layers)])\n",
126+
" static_shear_modulus_tuple = tuple([1.0e10 for i in range(num_layers)])\n",
127+
" bulk_viscosity_tuple = tuple([1.0e30 for i in range(num_layers)])\n",
128+
" shear_viscosity_tuple = tuple([1.0e30 for i in range(num_layers)])\n",
129+
" layer_type_tuple = tuple(['solid' for i in range(num_layers)])\n",
130+
" layer_is_static_tuple = tuple([False for i in range(num_layers)])\n",
131+
" layer_is_incompressible_tuple = tuple([False for i in range(num_layers)])\n",
132+
" shear_rheology_model_tuple = tuple([Maxwell() for i in range(num_layers)])\n",
133+
" bulk_rheology_model_tuple = tuple([Elastic() for i in range(num_layers)])\n",
134+
" thickness_fraction_tuple = tuple([1.0 / num_layers for i in range(num_layers)])\n",
135+
"\n",
136+
" inputs = (\n",
137+
" planet_radius,\n",
138+
" forcing_frequency,\n",
139+
" density_tuple,\n",
140+
" static_bulk_modulus_tuple,\n",
141+
" static_shear_modulus_tuple,\n",
142+
" bulk_viscosity_tuple,\n",
143+
" shear_viscosity_tuple,\n",
144+
" layer_type_tuple,\n",
145+
" layer_is_static_tuple,\n",
146+
" layer_is_incompressible_tuple,\n",
147+
" shear_rheology_model_tuple,\n",
148+
" bulk_rheology_model_tuple\n",
149+
" )\n",
150+
"\n",
151+
" # Make sure it works once\n",
152+
" print(f\"Working on #Layers = {num_layers}.\")\n",
153+
" output = build_rs_input_homogeneous_layers(*inputs, thickness_fraction_tuple=thickness_fraction_tuple, slice_per_layer=slices_per_layer, perform_checks=perform_checks)\n",
154+
"\n",
155+
" %timeit build_rs_input_homogeneous_layers(*inputs, thickness_fraction_tuple=thickness_fraction_tuple, slice_per_layer=slices_per_layer, perform_checks=perform_checks)"
156+
]
157+
},
158+
{
159+
"cell_type": "markdown",
160+
"id": "a3e7dcc4-da35-43c2-a6cb-f3aec3a62cf7",
161+
"metadata": {},
162+
"source": [
163+
"## `build_rs_input_from_data` Performance\n",
164+
"**v0.6.0:**\n",
165+
"slices_per_layer = 5; perform_checks=True; num_layers:\n",
166+
"- 1: 145us\n",
167+
"- 5: 586us\n",
168+
"- 10: 1.15ms\n",
169+
"- 15: 1.7ms\n",
170+
"- 20: 2.29ms\n",
171+
"- 50: 5.89ms\n",
172+
"- 100: 12ms\n",
173+
"\n",
174+
"slices_per_layer = 50; perform_checks=True; num_layers:\n",
175+
"- 1: 153 μs\n",
176+
"- 5: 658 μs\n",
177+
"- 10: 1.28 ms\n",
178+
"- 15: 1.92 ms\n",
179+
"- 20: 2.51 ms\n",
180+
"- 50: 6.58 ms\n",
181+
"- 100: 13.8 ms\n",
182+
"\n",
183+
"**v0.6.1:**\n",
184+
"slices_per_layer = 5; perform_checks=True; num_layers:\n",
185+
"- 1: 14.6 μs \n",
186+
"- 5: 18.7 μs\n",
187+
"- 10: 22.1 μs\n",
188+
"- 15: 26.1 μs\n",
189+
"- 20: 28.7 μs\n",
190+
"- 50: 51.3 μs\n",
191+
"- 100: 85.5 μs\n",
192+
"\n",
193+
"slices_per_layer = 50; perform_checks=True; num_layers:\n",
194+
"- 1: 20.3 μs\n",
195+
"- 5: 49.8 μs\n",
196+
"- 10: 71.5 μs\n",
197+
"- 15: 101 μs\n",
198+
"- 20: 129 μs\n",
199+
"- 50: 302 μs\n",
200+
"- 100: 595 μs"
201+
]
202+
},
203+
{
204+
"cell_type": "code",
205+
"execution_count": null,
206+
"id": "d4ab3cfc-301a-4d96-b135-c3acd41206bc",
207+
"metadata": {
208+
"scrolled": true
209+
},
210+
"outputs": [
211+
{
212+
"name": "stdout",
213+
"output_type": "stream",
214+
"text": [
215+
"Working on #Layers = 1.\n",
216+
"20.3 μs ± 196 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
217+
"Working on #Layers = 5.\n",
218+
"49.8 μs ± 7.7 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
219+
"Working on #Layers = 10.\n",
220+
"76.5 μs ± 3.07 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
221+
"Working on #Layers = 15.\n"
222+
]
223+
}
224+
],
225+
"source": [
226+
"slices_per_layer = 50\n",
227+
"perform_checks = False\n",
228+
"warnings = False\n",
229+
"\n",
230+
"for num_layers in (1, 5, 10, 15, 20, 50, 100):\n",
231+
" planet_radius = 1.0e6\n",
232+
" forcing_frequency = 1.0e-4\n",
233+
" layer_thickness = planet_radius / num_layers\n",
234+
" dr = layer_thickness / slices_per_layer\n",
235+
"\n",
236+
" # The dr addition below ensures there is a small error in the radius array that the helper has to fix\n",
237+
" radius_array = np.concatenate([np.linspace(layer_thickness * i + 0.1 * dr, layer_thickness * (i + 1), slices_per_layer) for i in range(num_layers)])\n",
238+
" density_array = np.linspace(10_000.0, 4_000.0, radius_array.size)\n",
239+
" static_bulk_modulus_array = np.linspace(1000.0e9, 250.0e9, radius_array.size)\n",
240+
" static_shear_modulus_array = np.linspace(250.0e9, 50.0e9, radius_array.size)\n",
241+
" bulk_viscosity_array = np.logspace(30, 26, radius_array.size)\n",
242+
" shear_viscosity_array = np.logspace(30, 18, radius_array.size)\n",
243+
" \n",
244+
" layer_upper_radius_tuple = tuple([(i+1) * layer_thickness for i in range(num_layers)])\n",
245+
" layer_type_tuple = tuple(['solid' for i in range(num_layers)])\n",
246+
" layer_is_static_tuple = tuple([False for i in range(num_layers)])\n",
247+
" layer_is_incompressible_tuple = tuple([False for i in range(num_layers)])\n",
248+
" shear_rheology_model_tuple = tuple([Maxwell() for i in range(num_layers)])\n",
249+
" bulk_rheology_model_tuple = tuple([Elastic() for i in range(num_layers)])\n",
250+
" thickness_fraction_tuple = tuple([1.0 / num_layers for i in range(num_layers)])\n",
251+
"\n",
252+
" inputs = (\n",
253+
" forcing_frequency,\n",
254+
" radius_array,\n",
255+
" density_array,\n",
256+
" static_bulk_modulus_array,\n",
257+
" static_shear_modulus_array,\n",
258+
" bulk_viscosity_array,\n",
259+
" shear_viscosity_array,\n",
260+
" layer_upper_radius_tuple,\n",
261+
" layer_type_tuple,\n",
262+
" layer_is_static_tuple,\n",
263+
" layer_is_incompressible_tuple,\n",
264+
" shear_rheology_model_tuple,\n",
265+
" bulk_rheology_model_tuple\n",
266+
" )\n",
267+
"\n",
268+
" # Make sure it works once\n",
269+
" print(f\"Working on #Layers = {num_layers}.\")\n",
270+
" output = build_rs_input_from_data(*inputs, perform_checks=perform_checks, warnings=warnings)\n",
271+
"\n",
272+
" %timeit build_rs_input_from_data(*inputs, perform_checks=perform_checks, warnings=warnings)"
273+
]
274+
}
275+
],
276+
"metadata": {
277+
"kernelspec": {
278+
"display_name": "Python 3 (ipykernel)",
279+
"language": "python",
280+
"name": "python3"
281+
},
282+
"language_info": {
283+
"codemirror_mode": {
284+
"name": "ipython",
285+
"version": 3
286+
},
287+
"file_extension": ".py",
288+
"mimetype": "text/x-python",
289+
"name": "python",
290+
"nbconvert_exporter": "python",
291+
"pygments_lexer": "ipython3",
292+
"version": "3.11.11"
293+
}
294+
},
295+
"nbformat": 4,
296+
"nbformat_minor": 5
297+
}

CHANGES.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# TidalPy Major Change Log
22

3+
### Version 0.6.1 (2025-01-11)
4+
5+
#### Benchmarks and Performance
6+
* Added performance benchmark for `TidalPy.RadialSolver.helpers`.
7+
8+
#### Fixes
9+
* Fixed memory leak that was occurring in the EOS Solver (therefore also RadialSolver) due to CyRK's CySolverSolution not being dereferenced (this is a problem with CyRK, but hack applied to TidalPy until a fix can be made to CyRK).
10+
11+
#### Performance
12+
* Improved `TidalPy.RadialSolver.helpers.build_rs_input_from_data` performance by factor of 10x to 150x depending on layer structure.
13+
* Improved `TidalPy.RadialSolver.helpers.build_rs_input_homogeneous_layers` performance by factor of 15% to 3.5x depending on layer structure.
14+
* Improved `TidalPy.RadialSolver.radial_solver` performance by around 10% depending on layer structure.
15+
316
## Version 0.6.0 (2025-01-07)
417
#### Removed
518
* Removed support for the older non-cythonized `TidalPy.radial_solver` module in favor of `TidalPy.RadialSolver`

Demos/prem_data.csv

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ radius,density,Vph,Vsh,mu,K,Visc
113113
5951000,3748.95,9236.31,4990.83,93380286530,1.95314E+11,1.00E+24
114114
5961000,3736.35,9185.11,4961.66,91981725679,1.9258E+11,1.00E+24
115115
5971000,3543.26,8905.24,4769.9,80616060219,1.73504E+11,1.00E+24
116-
5971000,3723.75,9133.92,4932.49,90596817738,1.89871E+11,1.00E+24
117116
5981000,3537.29,8886,4762.9,80244189155,1.72316E+11,1.00E+24
118117
5991000,3531.32,8866.77,4755.9,79873460911,1.71133E+11,1.00E+24
119118
6001000,3525.35,8847.53,4748.9,79503873733,1.69955E+11,1.00E+24

Documentation/RadialSolver/3 - Radial Solver Helpers.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ TidalPy's radial solver function is particular on the format of its inputs. It c
55
The helper functions described here are designed to give users an easy interface to provide data that is then translated into the inputs required by the `radial_solver` function.
66

77
These functions are not designed to be particularly efficient. So it is recommended to use them until you get comfortable with the kind of inputs `radial_solver` requires.
8-
At that point it would be more efficient to make the inputs correctly from the beginning and forego using these functions.
8+
At that point it would be more efficient to make the inputs correctly from the beginning and forego using these functions.
9+
That being said, benchmarking shows that they only add about a 2% -- 10% overhead depending on the layer structure.
910

1011
[^1]: If a crash does occur, please report it on TidalPy's GitHub issues page. Please include the exact inputs used.
1112

README.md

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

1212
---
1313

14-
<a href="https://github.com/jrenaud90/TidalPy/releases"><img src="https://img.shields.io/badge/TidalPy-0.6.0 Alpha-orange" alt="TidalPy Version 0.6.0 Alpha" /></a>
14+
<a href="https://github.com/jrenaud90/TidalPy/releases"><img src="https://img.shields.io/badge/TidalPy-0.6.1 Alpha-orange" alt="TidalPy Version 0.6.1 Alpha" /></a>
1515

1616
**Tidal Dynamics and Thermal-Orbital Evolution Software Suite Implemented in Cython and Python**
1717

Tests/Test_RadialSolver/test_a_helpers.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,13 @@ def test_build_rs_input_from_data(num_layers, num_slices, r0):
316316

317317
for layer_i in range(num_layers):
318318
if layer_i == 0:
319-
radius_array_new[0] == 0.0
319+
assert radius_array_new[0] == 0.0
320320
elif layer_i == (num_layers - 1):
321321
# One copy of upper radius at planet surface
322-
np.sum(radius_array_new == layer_upper_radius_tuple[layer_i]) == 1
322+
assert np.sum(radius_array_new == layer_upper_radius_tuple[layer_i]) == 1
323323
else:
324324
# Two copies of radius at interfaces
325-
np.sum(radius_array_new == layer_upper_radius_tuple[layer_i]) == 2
325+
assert np.sum(radius_array_new == layer_upper_radius_tuple[layer_i]) == 2
326326

327327
# Check that other properties match expectations
328328
first_index = np.argwhere(radius_array_new == layer_upper_radius_tuple[layer_i])[0]
@@ -332,7 +332,10 @@ def test_build_rs_input_from_data(num_layers, num_slices, r0):
332332
assert radius_array_new[first_index + 1] == layer_upper_radius_tuple[layer_i]
333333

334334
# Assert that physical properties are the same at this and below
335-
assert density_array_new[first_index] == density_array_new[first_index - 1]
335+
try:
336+
assert density_array_new[first_index] == density_array_new[first_index - 1]
337+
except:
338+
import pdb; pdb.set_trace()
336339
assert complex_bulk_array_new[first_index] == complex_bulk_array_new[first_index - 1]
337340
assert complex_shear_array_new[first_index] == complex_shear_array_new[first_index - 1]
338341
assert density_array_new[first_index] == density_array_new[first_index - 1]

0 commit comments

Comments
 (0)