# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# [Link to this document's Jupyter Notebook](./0415-PROJECT_Part2.ipynb)

# # Project Part 2: Benchmark and Optimization
#
# In this milestone you will provide a report which includes the results of your benchmark and optimization.  Your report will include a benchmark speeds on a single core and then a description of what you did to speed up the code and a graph of how much improvements you made over the benchmark.  Your final report should include the following:
#
# - Project Title
# - Motivating Image
# - Abstract
# - Methodology
# - Timing Results
# - Concluding Discussion and Future Work
# - References

# # Pyro
#
# By <NAME>

# ![pyro_logo](https://raw.githubusercontent.com/python-hydro/pyro2/main/www/logo.gif "Pyro Logo GIF")
#
# Image from: https://github.com/python-hydro/pyro2/blob/main/www/logo.gif
#
# ![pyro_example_plots](pyro_plots.png "Pyro Example Plots")
#
# Image from: https://pyro2.readthedocs.io/en/latest/intro.html

# ---
# # Abstract
#
# `pyro` is a software tool built in Python for modeling hydrodynamics Partial Differential Equations (PDEs). PDEs arise in many areas of physics and astronomy, including waves, transport, diffusion, heat, vibration, and even quantum mechanics. More specifically, PDEs can be used to model gravitational waves, magnetohydrodynamics, and radiative transport. As a computational tool, `pyro` could be useful in solvig a variety of astrophysical problems, especially as computational astrophysics grows as a field. Computational astrophysics can serve as a substitute for "experimental" astrophysics, since many astrophysical systems can not be reasonably reproduced in a laboratory setting. Furthermore, computational astrophysics serves as a bridge between theoretical predictions and observations. For this project, I cloned the repository to the HPCC and ran some of the serial code, then used `PyPy` to try and speed up the execution time. `PyPy` was unable to improve the execution time, with specific reasons for this discussed later.

# ---
# # Methodology
#
# &#9989;  Provide a more detailed description about what you did for this project.  Include detailed instructions needed to reproduce the project.  These instructions should be detailed enough for a future student to be able to read the report, reproduce your results and pick up where you left off. 
#
# First, we need to get `pyro` working. The steps for installing and running `pyro`:
# 1. Clone my [forked pyro repository](https://github.com/priesbr1/CMSE401_pyro2_project) to the HPCC (`git clone <pyro_repo> <target_directory_name>`)
# 2. Ensure Python and necessary packages are installed/available
#    * numpy, matplotlib, h5py, numba (`numba` is only used in certain solvers)
#    * These packages should be available with the default Python installation
# 3. Run serial code (`./pyro.py <solver> <problem_type> <inputs>`)
#    * Optional `vis.dovis=0` flag to turn off visualization
#
# $\quad$
#
# As an alternative, you can run the `pyro` code as a job from the `CMSE401_deliverables` directory using the following command:
#
# ```bash
# sbatch pyro_serial.sb <solver> <problem_type> <problem_inputs>
# ```
# This will run the same `pyro` command as in Step 3, with the visualization turned off. An explicit test example is provided in `pyro_advection_smooth.sb`.
#
# ***
#
# After completing the above steps, we need to get `PyPy` working. The steps for installing and running `PyPy`:   
#
# **Note**: if you cloned the forked repository above, Steps 1 and 2 should already be complete.
#
# 1. Download [pypy](https://www.pypy.org/download_advanced.html#installing) to the HPCC
#    * You should download the newest Linux 64 bit version
#    * I used a program called WinSCP to copy from my local machine to the HPCC, but you should be able to download directly using      a command like `wget` or `curl`
# 2. Unpack tar file (`tar xf <pypy_file.tar.bz>`)
# 3. Add pypy/bin directory to path (`PATH=$PATH:<path_to_pypy/pypy_directory/bin>`)
#    * Assuming `pypy` was unpacked in the main repo directory, `path_to_pypy` would be the main repo directory, and                    `pypy_directory` should have a similar name to the tar file
# 4. Install ensurepip (`pypy -m ensurepip`)
# 5. Install pypy packages (`pypy -mpip install <package>`)
#    * wheel, numpy, matplotlib, h5py, numba (`numba` is only used in certain solvers)
# 6. Run pypy code (`pypy ./pyro.py <solver> <problem_type> <inputs>`)
#    * Optional `vis.dovis=0` flag to turn off visualization
#
# $\quad$
#
# As an alterative, you can run the `pyro` code with `PyPy` as a job from the `CMSE401_deliverables` directory using the following command:
#
# ```bash
# sbatch pyro_pypy.sb <solver> <problem_type> <problem_inputs>
# ```
#
# This will run the same `pyro` command as in Step 6, with the visualization turned off.

# ---
# # Timing Results
#
# Information on the number of users present is not provided, as times were so short that number of users present on a node while running should not have significantly impacted the program execution time. The times listed are the main `pyro` time output with visualization disabled. Two of the timing results are not provided due to an error in the `PyPy`/`h5py` interface. It is not entirely clear why this occurred or why it occurred with specific combinations of nodes/solvers/problems. The node labels are abbreviated as follows:
#
# * k20: dev-intel14-k20
# * k80: dev-intel16-k80
# * v100: dev-amd20-v100
#
# The specific `css` node that the job ran on is specified in the plot title.

# Imports
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
# %matplotlib inline

# +
# Serial Timing Results
k20_smooth_serial = np.array([0.8832, 2.0607, 101.8441])
k20_tophat_serial = np.array([0.2560, 0.7529, 106.3031])
k80_smooth_serial = np.array([0.5442, 1.1280, 59.7124])
k80_tophat_serial = np.array([0.2063, 0.4790, 58.6220])
v100_smooth_serial = np.array([0.4151, 0.9430, 48.1898])
v100_tophat_serial = np.array([0.1635, 0.3895, 46.4991])
job_smooth_serial = np.array([0.9602, 2.3117, 107.3148])
job_tophat_serial = np.array([0.2665, 0.7899, 109.1272])

# PyPy Timing Results
k20_smooth_pypy = np.array([3.4750, 8.8173, 417.9936])
k20_tophat_pypy = np.array([1.3090, None, 418.9023])
k80_smooth_pypy = np.array([3.0369, 7.0060, 468.4594])
k80_tophat_pypy = np.array([0.8817, 2.8278, 487.3456])
v100_smooth_pypy = np.array([None, 5.1892, 286.7580])
v100_tophat_pypy = np.array([0.6048, 1.9467, 250.9401])
job_smooth_pypy = np.array([4.1386, 9.6141, 551.3310])
job_tophat_pypy = np.array([1.2361, 3.5570, 543.2876])

# Set custom legend
legend_elements = [Line2D([0], [0], color="blue", lw=2, label="k20"),
                   Line2D([0], [0], color="orange", lw=2, label="k80"),
                   Line2D([0], [0], color="green", lw=2, label="v100"),
                   Line2D([0], [0], color="red", lw=2, label="css (job)"),
                   Line2D([0], [0], color="black", marker='o', lw=0, markerfacecolor="black", markersize=5, label="smooth"),
                   Line2D([0], [0], color="black", marker='^', lw=0, markerfacecolor="black", markersize=5, label="tophat")]

# Set up subplots
fig, ax = plt.subplots(1,2,figsize=(10,5))

# Serial
ax[0].axhline(10**0, color="gray", alpha=0.5) # Gridlines
ax[0].axhline(10**1, color="gray", alpha=0.5)
ax[0].axhline(10**2, color="gray", alpha=0.5)
ax[0].plot(k20_smooth_serial, color="blue", linewidth=0, marker='o')
ax[0].plot(k20_tophat_serial, color="blue", linewidth=0, marker='^')
ax[0].plot(k80_smooth_serial, color="orange", linewidth=0, marker='o')
ax[0].plot(k80_tophat_serial, color="orange", linewidth=0, marker='^')
ax[0].plot(v100_smooth_serial, color="green", linewidth=0, marker='o')
ax[0].plot(v100_tophat_serial, color="green", linewidth=0, marker='^')
ax[0].plot(job_smooth_serial, color="red", linewidth=0, marker='o')
ax[0].plot(job_tophat_serial, color="red", linewidth=0, marker='^')
ax[0].set_xticks(np.arange(3))
ax[0].set_xticklabels(["advection", "advection_rk", "advection_weno"]) # x-axis solver labels
ax[0].set_yscale('log')
ax[0].set_ylim(10**(-1), 10**(3)) # Same scale
ax[0].set_ylabel("Main Execution Time [sec]")
ax[0].set_title("Serial Pyro (job node css-059)")

# PyPy
ax[1].axhline(10**0, color="gray", alpha=0.5) # Gridlines
ax[1].axhline(10**1, color="gray", alpha=0.5)
ax[1].axhline(10**2, color="gray", alpha=0.5)
ax[1].plot(k20_smooth_pypy, color="blue", linewidth=0, marker='o')
ax[1].plot(k20_tophat_pypy, color="blue", linewidth=0, marker='^')
ax[1].plot(k80_smooth_pypy, color="orange", linewidth=0, marker='o')
ax[1].plot(k80_tophat_pypy, color="orange", linewidth=0, marker='^')
ax[1].plot(v100_smooth_pypy, color="green", linewidth=0, marker='o')
ax[1].plot(v100_tophat_pypy, color="green", linewidth=0, marker='^')
ax[1].plot(job_smooth_pypy, color="red", linewidth=0, marker='o')
ax[1].plot(job_tophat_pypy, color="red", linewidth=0, marker='^')
ax[1].set_xticks(np.arange(3))
ax[1].set_xticklabels(["advection", "advection_rk", "advection_weno"]) # x-axis solver labels
ax[1].set_yscale('log')
ax[1].set_ylim(10**(-1), 10**(3)) # Same scale
ax[1].set_title("PyPy Pyro (job node css-124)")
ax[1].legend(handles=legend_elements, loc="best")

fig.suptitle("Pyro Timing/Scaling Study Results")
fig.tight_layout()
# -

# Based on the results above, it is clear that `PyPy` was ineffective at speeding up the `pyro` code. One reason for this is that `PyPy` is most effective on longer-running code. Although all of the examples shown here are iterative/looping processes, all finished in less than 10 minutes, meaning that the overhead involved with `PyPy` caused more harm than good.
#
# Across the entire timing study, running with the `tophat` inputs tended to produce faster execution times than the `smooth` inputs. The `advection_weno` solver was also the slowest by far, taking roughly 2 minutes (serial) or 8 minutes (`PyPy`) to run in some cases. The only time the `tophat` inputs did not outperform the `smooth` inputs was with the `advection_weno` solver.
#
# Futhermore, in all cases, the ordering of execution time (from slowest to fastest) was `css-059/css-124`, `k20`, `k80`, and `v100`. This makes sense, as the newer hardware on newer development nodes led to faster execution times. The added overhead of submitting a job to the cluster may have contributed to the slow performance of the `css` nodes. If the nodes used older hardware, that could also explain the slower performance. 

# ---
# # Concluding Discussion and Future Work
#
# `pyro` is a programming tool that can be used to solve hydrodynamics PDEs that appear in a variety of astrophysical situations. An attempt to speed it up with `PyPy` was unsuccessful. This is most likely because the `pyro` examples tested take less than 10 minutes to run, which is likely not long enough for `PyPy` to match or improve upon the serial results.
#
# If we wanted to use `PyPy` to improve the results, we would need to run the code for much longer -- something more on the order of hours. At those scales, the speed-up capabilities of `PyPy` may overcome the overhead costs. As an alternative to `PyPy`, we could use another drop-in compiler like `Cython`/`CPython`. We could also try expanding upon `pyro`'s current `numba` implementation, as `numba` is only used in a few of the solvers, none of which were featured here.

# ---
# # References
#
# `pyro` repository/documentation:
# * https://github.com/python-hydro/pyro2   
# * https://pyro2.readthedocs.io/en/latest/intro.html   
#
# `pypy` background/installation/setup:
# * https://www.infoworld.com/article/3385127/what-is-pypy-faster-python-without-pain.html   
# * https://doc.pypy.org/en/latest/install.html   
# * https://www.pypy.org/download_advanced.html#installing   
# * https://realpython.com/pypy-faster-python/   

# -----
# ### Congratulations, you are done!
#
# Now, you just need to create a second directory in your git repository and include your report as an md or ipynb file in the directory along with any additional figures and files needed to reproduce the results.  You instructor should already have your git repository and be able to pull in your changes. 

# Written by Dr. <NAME>, Michigan State University
# <a rel="license" href="http://creativecommons.org/licenses/by-nc/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc/4.0/">Creative Commons Attribution-NonCommercial 4.0 International License</a>.

# ----

StarcoderdataJupyterScriptsDedupFiltered