diff --git a/notebooks/01--Introduction.ipynb b/notebooks/01--Introduction.ipynb index 59aaaa7142e9ea945b5222986a752cbe9ca0c7fe..a2298c04bf3667c52ad1a937545e952e71c9d3ea 100644 --- a/notebooks/01--Introduction.ipynb +++ b/notebooks/01--Introduction.ipynb @@ -108,7 +108,7 @@ "* Scientific Computing with Python: NumPy and SciPy\n", "* Performance: Cython, JIT (Numba, JAX), C/Fortran interfacing\n", "* Parallelism: multithreading, multiprocessing, GPU computing, Dask, mpi4py\n", - "* Software Engineering, Packaging, Profiling, Visualization" + "* Software Engineering, Packaging, Profiling, Testing" ] }, { @@ -141,6 +141,7 @@ "\n", "* Practical hands-on approach with code examples\n", "* Presentation is based on Jupyter notebooks\n", + "* Exercises based on Jupyter notebooks complement the presentations\n", "* Course material available for download at \n", " https://gitlab.mpcdf.mpg.de/mpcdf/python-for-hpc-exercises" ] @@ -220,13 +221,6 @@ "$ conda activate pyhpc\n", "```" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/notebooks/04--BasicHPC.ipynb b/notebooks/04--BasicHPC.ipynb index c41db26615304d0de808dcd489c30cd42683dd99..cbc7de15bf98a0ec579a67e148b7cc01b84deaa8 100644 --- a/notebooks/04--BasicHPC.ipynb +++ b/notebooks/04--BasicHPC.ipynb @@ -44,14 +44,14 @@ "\n", "* High performance computing: \"computing at bottlenecks of the hardware\" (G. Hager, RRZE)\n", "* Write *efficient software* to use *maximum hardware potential*\n", + "* Needed:\n", + " * Understand hardware\n", + " * Understand how software is executed on hardware\n", "* Common bottlenecks:\n", " * Floating point operations\n", " * Memory access\n", " * Input/Output\n", " * Communication\n", - "* Needed:\n", - " * Understand hardware\n", - " * Understand how software is executed on hardware\n", "* Here: only very basics, for more in-depth information, see courses from HLRS, LRZ and RRZE" ] }, diff --git a/notebooks/08--Diffusion.ipynb b/notebooks/08--Diffusion.ipynb index 588d876204579fe268cf6a923a38c2d8cca1b537..7a46efe3a039264acd642d83381a352e9c9123cf 100644 --- a/notebooks/08--Diffusion.ipynb +++ b/notebooks/08--Diffusion.ipynb @@ -142,12 +142,15 @@ }, "outputs": [], "source": [ - "def init(val=0.5):\n", + "def init(val=0.5, with_ghosts=True):\n", " \"\"\"Set up a 2d NumPy array with some initial value pattern.\"\"\"\n", " x = np.linspace(0., 4.*np.pi, num=n_points+2)\n", " y = np.linspace(0., 4.*np.pi, num=n_points+2)\n", " grid = val * np.outer(np.sin(x)**4, np.sin(y)**4)\n", - " return grid" + " if with_ghosts:\n", + " return grid\n", + " else:\n", + " return grid[1:-1,1:-1]" ] }, { @@ -289,7 +292,7 @@ } ], "source": [ - "from scipy.ndimage.filters import laplace as scipy_laplacian\n", + "from scipy.ndimage import laplace as scipy_laplacian\n", "\n", "def evolve_scipy(grid, grid_tmp, n_points, dt, D):\n", " \"\"\"Time step based on the SciPy Laplacian.\"\"\"\n", @@ -316,7 +319,7 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=False)\n", "solution_scipy = main_loop(evolve_scipy, grid)" ] }, @@ -357,7 +360,7 @@ ], "source": [ "%%time\n", - "grid = init()" + "grid = init(with_ghosts=False)" ] }, { @@ -380,7 +383,7 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=False)\n", "solution_scipy = main_loop(evolve_scipy, grid)" ] }, @@ -508,10 +511,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=False)\n", "solution_roll = main_loop(evolve_np_roll, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_roll))" + ] + }, { "cell_type": "code", "execution_count": 17, @@ -533,7 +545,7 @@ } ], "source": [ - "plot_grids(init(), solution_roll)" + "plot_grids(init(with_ghosts=False), solution_roll)" ] }, { @@ -578,10 +590,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=False)\n", "solution_roll = main_loop(evolve_np_inplace_roll, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_roll))" + ] + }, { "cell_type": "code", "execution_count": 20, @@ -603,7 +624,7 @@ } ], "source": [ - "plot_grids(init(), solution_roll)" + "plot_grids(init(with_ghosts=False), solution_roll)" ] }, { @@ -636,6 +657,15 @@ " grid[ :, 0] = grid[ :,-2]" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "grid = init(with_ghosts=True)" + ] + }, { "cell_type": "code", "execution_count": 22, @@ -659,6 +689,15 @@ "apply_periodic_bc_python(grid, n_points)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "grid = init(with_ghosts=False)" + ] + }, { "cell_type": "code", "execution_count": 23, @@ -721,10 +760,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_np_slicing = main_loop(evolve_np_slicing, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_np_slicing[1:-1,1:-1]))" + ] + }, { "cell_type": "code", "execution_count": 26, @@ -791,10 +839,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_np_slicing = main_loop(evolve_np_inplace_slicing, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_np_slicing[1:-1,1:-1]))" + ] + }, { "cell_type": "code", "execution_count": 29, @@ -910,7 +967,7 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "#main_loop(evolve_cython, grid)\n", "\n", "# measured wall clock time during lunch break: 25 minutes!!!" @@ -4706,9 +4763,9 @@ " cdef int i, j\n", " for j in range(n_points + 2):\n", " grid[ 0, j] = grid[n_points, j] # grid[ 0, j] = grid[-2, j]\n", - " grid[n_points-1, j] = grid[ 1, j] # grid[-1, j] = grid[ 1, j]\n", + " grid[n_points+1, j] = grid[ 1, j] # grid[-1, j] = grid[ 1, j]\n", " for i in range(n_points + 2):\n", - " grid[ i, n_points-1] = grid[ i, 1] # grid[ i,-1] = grid[ i, 1]\n", + " grid[ i, n_points+1] = grid[ i, 1] # grid[ i,-1] = grid[ i, 1]\n", " grid[ i, 0] = grid[ i, n_points] # grid[ i, 0] = grid[ i,-2]\n", "\n", "@cython.boundscheck(False) # turn off bounds-checking\n", @@ -4749,6 +4806,15 @@ "solution_cython = main_loop(evolve_cython, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_cython[1:-1,1:-1]))" + ] + }, { "cell_type": "code", "execution_count": 38, @@ -4809,9 +4875,9 @@ " cdef int i, j\n", " for j in range(n_points + 2):\n", " grid[ 0, j] = grid[n_points, j] # grid[ 0, j] = grid[-2, j]\n", - " grid[n_points-1, j] = grid[ 1, j] # grid[-1, j] = grid[ 1, j]\n", + " grid[n_points+1, j] = grid[ 1, j] # grid[-1, j] = grid[ 1, j]\n", " for i in range(n_points + 2):\n", - " grid[ i, n_points-1] = grid[ i, 1] # grid[ i,-1] = grid[ i, 1]\n", + " grid[ i, n_points+1] = grid[ i, 1] # grid[ i,-1] = grid[ i, 1]\n", " grid[ i, 0] = grid[ i, n_points] # grid[ i, 0] = grid[ i,-2]\n", "\n", "@cython.boundscheck(False) # turn off bounds-checking\n", @@ -5023,9 +5089,9 @@ " cdef int i, j\n", " for j in range(n_points + 2):\n", " grid[ 0, j] = grid[n_points, j] # grid[ 0, j] = grid[-2, j]\n", - " grid[n_points-1, j] = grid[ 1, j] # grid[-1, j] = grid[ 1, j]\n", + " grid[n_points+1, j] = grid[ 1, j] # grid[-1, j] = grid[ 1, j]\n", " for i in range(n_points + 2):\n", - " grid[ i, n_points-1] = grid[ i, 1] # grid[ i,-1] = grid[ i, 1]\n", + " grid[ i, n_points+1] = grid[ i, 1] # grid[ i,-1] = grid[ i, 1]\n", " grid[ i, 0] = grid[ i, n_points] # grid[ i, 0] = grid[ i,-2]\n", "\n", "@cython.boundscheck(False) # turn off bounds-checking\n", @@ -5067,6 +5133,15 @@ "solution_cython_parallel = main_loop(evolve_cython_parallel, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_cython_parallel[1:-1,1:-1]))" + ] + }, { "cell_type": "code", "execution_count": 45, @@ -5221,7 +5296,7 @@ }, "outputs": [], "source": [ - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba = main_loop(evolve_python_numba, grid)" ] }, @@ -5246,10 +5321,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba = main_loop(evolve_python_numba, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_numba[1:-1,1:-1]))" + ] + }, { "cell_type": "markdown", "metadata": { @@ -5303,7 +5387,7 @@ }, "outputs": [], "source": [ - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba = main_loop(evolve_python_numba_parallel, grid)" ] }, @@ -5327,10 +5411,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba = main_loop(evolve_python_numba_parallel, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_numba[1:-1,1:-1]))" + ] + }, { "cell_type": "code", "execution_count": 54, @@ -5422,7 +5515,7 @@ }, "outputs": [], "source": [ - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba = main_loop(evolve_np_slicing_numba_parallel, grid)" ] }, @@ -5446,10 +5539,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba = main_loop(evolve_np_slicing_numba_parallel, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_numba[1:-1,1:-1]))" + ] + }, { "cell_type": "code", "execution_count": 59, @@ -5524,7 +5626,7 @@ }, "outputs": [], "source": [ - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba_stencil = main_loop(evolve_numba_stencil, grid)" ] }, @@ -5548,10 +5650,19 @@ ], "source": [ "%%time\n", - "grid = init()\n", + "grid = init(with_ghosts=True)\n", "solution_numba_stencil = main_loop(evolve_numba_stencil, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_numba_stencil[1:-1,1:-1]))" + ] + }, { "cell_type": "code", "execution_count": 63, @@ -5661,7 +5772,7 @@ "@jit\n", "def evolve_np_roll_jax(grid, n_points, dt, D):\n", " \"\"\"Time step based on the NumPy-roll-Laplacian.\"\"\"\n", - " return grid_tmp.at[:].set(grid + dt * D * laplacian_np_roll(grid))" + " return grid.at[:].set(grid + dt * D * laplacian_np_roll(grid))" ] }, { @@ -5682,7 +5793,7 @@ } ], "source": [ - "grid = init()\n", + "grid = init(with_ghosts=False)\n", "solution_jax = main_loop_jax(evolve_np_roll_jax, grid)" ] }, @@ -5705,10 +5816,19 @@ ], "source": [ "%%timeit\n", - "grid = init()\n", + "grid = init(with_ghosts=False)\n", "solution_jax = main_loop_jax(evolve_np_roll_jax, grid)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert(np.allclose(solution_scipy, solution_jax))" + ] + }, { "cell_type": "code", "execution_count": 68, diff --git a/notebooks/11--Software_Engineering.ipynb b/notebooks/11--Software_Engineering.ipynb index 7241fa4d9a87d7d0edddf3fad19b2004e9a2fed7..e6408d3f9a60d4a1313d3101d9a418ba1412ae6a 100644 --- a/notebooks/11--Software_Engineering.ipynb +++ b/notebooks/11--Software_Engineering.ipynb @@ -535,7 +535,7 @@ "## PyPI, the Python Package Index\n", "* PyPI is the online software repository for Python\n", "* https://pypi.python.org/pypi\n", - "* Contains nearly 330.000 packages (Oct 2021)\n", + "* Contains nearly 590.000 packages (Nov 2024)\n", "* Zip files, tar balls, wheel archives are accepted \n", " (typically generated locally by front-end, e.g., `python -m build`)\n", "* Anybody may upload packages after registration"