{"action":"created","comment":{"url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments/67623783","id":67623783,"diff_hunk":"@@ -0,0 +1,1022 @@\n+:author: Prabhu Ramachandran\n+:email: prabhu@aero.iitb.ac.in\n+:institution: Department of Aerospace Engineering\n+:institution: IIT Bombay, Mumbai, India\n+:corresponding:\n+:bibliography: references\n+\n+----------------------------------------------------------------------------------------\n+PySPH: a reproducible and high-performance framework for smoothed particle hydrodynamics\n+----------------------------------------------------------------------------------------\n+\n+.. class:: abstract\n+\n+    Smoothed Particle Hydrodynamics (SPH) is a general purpose technique to\n+    numerically compute the solutions to partial differential equations.  The\n+    method is grid-free and uses particles to discretize the various\n+    properties of interest.  The method is Lagrangian and particles are moved\n+    with the local velocity.\n+\n+    PySPH is an open source framework for Smoothed Particle Hydrodynamics.  It\n+    is implemented in a mix of Python and Cython.  It is designed to be easy\n+    to use on multiple platforms, high-performance and support parallel\n+    execution.  Users write pure-Python code and HPC code is generated on the\n+    fly, compiled, and executed.  PySPH supports OpenMP and MPI for\n+    distributed computing.  This is transparent to the user.  PySPH is also\n+    designed to make it easy to perform reproducible research.  In this paper\n+    we discuss the design and implementation of PySPH.\n+\n+\n+Background and Introduction\n+----------------------------\n+\n+SPH (Smoothed Particle Hydrodynamics) is a general purpose technique to\n+numerically compute the solutions to partial differential equations.  The\n+method is grid-free and uses particles to discretize the various properties of\n+interest.  The method is Lagrangian and particles are moved with the local\n+velocity.  The method was originally developed for astrophysical problems\n+:cite:`lucy77`, :cite:`monaghan77` (compressible gas-dynamics) but has since\n+been extended to simulate incompressible fluids\n+:cite:`sph:fsf:monaghan-jcp94`, solid mechanics :cite:`sph-elastic:gray:2001`,\n+free-surface problems :cite:`sph:fsf:monaghan-jcp94` and a variety of other\n+problems.  Monaghan :cite:`monaghan-review:2005`, provides a good review of\n+the method.\n+\n+The SPH method is relatively easy to implement.  This has resulted in a large\n+number of schemes and implementations proposed by various researchers.  It is\n+often difficult to reproduce published results due to the variety of\n+implementations.  While a few standard packages like (SPHysics\n+:cite:`sphysics`, DualSPHysics :cite:`dualsphysics`, JOSEPHINE\n+:cite:`josephine-sph:cpc:2015`, GADGET-2 :cite:`gadget2-springel:mnras:2005`\n+etc.)  exist, they are usually tailor-made for particular applications and are\n+not general purpose.  They are all implemented in FORTRAN (77 or 90) or C.\n+They do not have a convenient Python interface.\n+\n+Our group has been developing PySPH (http://pysph.bitbucket.org) over the last\n+5 years.  PySPH is open source, and distributed under the new BSD license.\n+Our initial implementation was based on Cython :cite:`behnel2010cython` and\n+also featured some parallelization using MPI.  This was presented at SciPy\n+2010 :cite:`PR-pysph-scipy-2010`.  Unfortunately, this previous version of\n+PySPH, proved difficult to use as users were forced to implement most of their\n+code in Cython.  This was not a matter of simply writing a few high\n+performance functions in Cython.  Our library is object oriented and\n+supporting a new SPH formulation would require subclassing one or more classes\n+and this would need to be done with Cython.  Our type system also ended up\n+becoming more rigid because if we desired performance as well as a general\n+purpose code, all the types needed to be pre-defined.  In addition, writing\n+all this in Cython meant that users had to manage compilation and linking the\n+Cython code during development.  This was not pleasant.\n+\n+It was felt that we might as well have implemented it all in C++ and exposed a\n+Python interface to that.  A traditional compiled language has more developer\n+tooling around it.  For example debugging, performance tuning, profiling would\n+all be easier if everything were written in C or C++.  Unfortunately, such a\n+mixed code-base would not be as easy to use, extend or maintain as a largely\n+pure Python library.  In our experience, a pure Python library is a lot easier\n+for say an undergraduate student to grasp and use over a C/C++ code.  Others\n+are also finding this to be true :cite:`py:nature:2015`.  Many of the top US\n+universities are teaching Python as their first language\n+:cite:`py:teaching-us`. This means that a Python library would also be easier\n+for relatively inexperienced programmers.  It is also true that a Python\n+library would be easier and shorter to write for the other\n+non-high-performance aspects (which is often a significant amount of code).\n+So it seemed that our need for performance was going against our desire for an\n+easy to use Python library that could be used by programmers who were not\n+C/C++ developers.\n+\n+In early 2013, we redesigned PySPH so that users were able to implement an\n+entire simulation using pure Python.  This was done by auto-generating HPC\n+code from the pure Python code that users provided.  This version ended up\n+being faster than our original Cython implementation!  Since we were\n+auto-generating code, with a bit of additional effort it was possible to\n+support OpenMP as well.  The external user API did not change so users did not\n+have to modify their code at all to benefit from this development.  PySPH has\n+thus matured into an easy to use, yet high-performance framework where users\n+can develop their schemes in pure Python and yet obtain performance close to\n+that of a lower-level language implementation.  PySPH has always supported\n+running on a cluster of machines via MPI.  This is seamless and a serial\n+script using PySPH can be run with almost no changes using MPI.\n+\n+PySPH features a reasonable test-suite and we use continuous integration\n+servers to test it on Linux and Windows.  Our documentation is hosted on\n+http://pysph.readthedocs.org.  The framework supports several of the standard\n+SPH schemes.  A suite of about 30 examples are provided.  These are shipped as\n+part of the sources and installed when a user does a pip install for example.\n+The examples are written in a way that makes it easy to extend and also\n+perform comparisons between schemes.  These features make PySPH well suited\n+for reproducible numerical work.  In fact one of our recent papers was written\n+such that every figure in the paper is automatically generated using PySPH.\n+\n+In this paper we discuss the use, design, and implementation of PySPH.  In the\n+next section we provide a high-level overview of the SPH method.\n+\n+Smoothed Particle Hydrodynamics\n+-------------------------------\n+\n+The SPH method works by approximating the identity:\n+\n+.. math::\n+\n+   f(x) = \\int f(x') \\delta (x-x') dx',\n+\n+where, :math:`\\delta` is the Dirac Delta distribution.  This identity is\n+approximated using:\n+\n+.. math::\n+   :label: eq:delta-approx\n+\n+   f(x) \\approx \\int f(x') W (x-x', h) dx',\n+\n+where :math:`W` is a smooth and compact function and is called the kernel.  It\n+is an approximate Dirac delta distribution that is parametrized on the\n+parameter :math:`h` and :math:`W \\rightarrow \\delta` as :math:`h\\rightarrow\n+0`.  :math:`h` is called the smoothing length or smoothing radius of the\n+kernel.  The kernel typically will need to satisfy a few properties if this\n+approximation is to be accurate.  Notably, its area should be unity and if it\n+is symmetric, it can be shown that the approximation is at least second order\n+in :math:`h`.  The above equation can be discretized as,\n+\n+.. math::\n+   :label: eq:sph-discr\n+\n+   f(x) \\approx \\langle f(x) \\rangle = \\sum_{j \\in \\mathcal{N}(x)} W(x-x_j, h) f(x_j) \\Delta x_j,\n+\n+where :math:`x_j` is the position of the particle :math:`j`, :math:`\\Delta\n+x_j` is the volume associated with this particle.  :math:`\\mathcal{N}(x)` is the\n+set of particle indices that are in the neighborhood of :math:`x`.  In SPH\n+each particle carries a mass :math:`m` and associated density :math:`\\rho`\n+with it and the particle volume is typically chosen as\n+:math:`\\Delta x_j = m_j/\\rho_j`.  This results in the following SPH\n+approximation for a function,\n+\n+.. math::\n+   :label: eq:sph-approx\n+\n+   <f(x)> = \\sum_{j \\in \\mathcal{N}(x)} \\frac{m_j}{\\rho_j} W(x-x_j, h) f(x_j).\n+\n+Derivatives of functions at a location :math:`x_i` are readily approximated by\n+taking the derivative of the smooth kernel.  This results in,\n+\n+.. math::\n+   :label: eq:deriv-sph-approx\n+\n+   \\frac{\\partial f_i}{\\partial x_i} = \\sum_{j \\in \\mathcal{N}(x)}\n+        \\frac{m_j}{\\rho_j} (f_j - f_i) \\frac{\\partial W_{ij}}{\\partial x_i}.\n+\n+Here :math:`W_{ij} = W(x_i - x_j)`.  Similar discretizations exist for the\n+divergence and curl operators.  Given that derivatives can be approximated one\n+can solve differential equations fairly easily.  For example the conservation\n+of mass equation for a fluid can be written as,\n+\n+.. math::\n+   :label: eq:cons-mass\n+\n+   \\frac{d \\rho}{dt} = - \\rho \\nabla \\cdot \\vec{v},\n+\n+where :math:`v` is the velocity of the fluid and the LHS is the material or\n+total derivative of the density.  The equation :ref:`eq:cons-mass` is in a\n+Lagrangian form, in that it represents the rate of change of density as one is\n+moving locally with the fluid.  If an SPH discretization of this equation were\n+performed we would get,\n+\n+.. math::\n+   :label: eq:sph-continuity\n+\n+   \\frac{d \\rho_i}{d t} =  -\\rho_i \\sum_{j \\in \\mathcal{N}(x)}\n+   \\frac{m_j}{\\rho_j} \\vec{v}_{ji} \\cdot \\nabla_i W_{ij},\n+\n+where :math:`\\vec{v}_{ji} = \\vec{v}_j - \\vec{v}_i`.  This equation is typical\n+of most SPH discretizations.  SPH can therefore be used to discretize any\n+differential equation.  This works particularly well for a variety of\n+continuum mechanics problems.  Consider the momentum equation for an inviscid\n+fluid,\n+\n+.. math::\n+   :label: eq:momentum\n+\n+   \\frac{d \\vec{u}}{dt} = - \\frac{1}{\\rho} \\nabla p\n+\n+A typical SPH discretization of this could be written as,\n+\n+.. math::\n+   :label: eq:sph-momentum\n+\n+   \\frac{d \\vec{u_i} }{dt} = -\\sum_j m_j \\left ( \\frac{p_j}{\\rho_j^2} +\n+   \\frac{p_i}{\\rho_i^2} \\right) \\nabla W_{ij}\n+\n+\n+More details of these and various other equations can be seen in the review by\n+Monaghan :cite:`monaghan-review:2005`.  It is easy to see that equations\n+:ref:`eq:sph-continuity` and :ref:`eq:sph-momentum` are ordinary differential\n+equations that govern the rate of change of the density and velocity of a\n+fluid particle.  In principle, one can integrate these ODEs to obtain the flow\n+solution given a suitable initial condition and appropriate boundary\n+conditions.\n+\n+\n+Numerical implementation\n+-------------------------\n+\n+As discussed in the previous section, in an SPH scheme, the field properties\n+are first discretized into particles carrying them.  Partial differential\n+equations are reduced to a system of coupled ordinary differential equations\n+and discretized using an SPH approximation.  This results in a system of ODEs\n+for each particle.  These ODEs need to be integrated in time along with\n+suitable boundary and initial conditions in order to solve a particular\n+problem.  To summarize, a typical SPH computation proceeds as follows,\n+\n+- Given an initial condition, the field variables are discretized into\n+  particles carrying the various properties.\n+- Depending on the scheme used to integrate the ODEs, the RHS of the ODEs\n+  needs to be computed (see equations :ref:`eq:sph-continuity` and\n+  :ref:`eq:sph-momentum`).  These RHS terms are called \"accelerations\" or\n+  \"acceleration terms\".\n+- Once the RHS is computed, the ODE can be integrated using a suitable scheme\n+  and the fluid properties are found at the next timestep.\n+\n+The RHS is typically computed as follows:\n+\n+- Initalize the particle accelerations (i.e. the RHS terms).\n+- For each particle in the flow, identify the neighbors of the particle which\n+  will influence the particle.\n+- For each neighbor compute the acceleration due to that particle and\n+  increment the acceleration.\n+\n+Given the total accelerations, the ODEs can be readily integrated with a\n+variety of schemes.  Any general purpose abstraction of the SPH method must\n+hence provide functionality to:\n+\n+1. Easily discretize properties into particles.  This is easily done with\n+   ``numpy`` arrays representing the property values in Python.\n+2. Given a particle, identify the neighbors that influence the particle.  This\n+   is typically called Nearest Neighbor Particle Search (NNPS) in the\n+   literature.\n+3. Define the interactions between the particles, i.e. an easy way to specify\n+   the inter particle accelerations.  In PySPH these are called \"Equations\".\n+4. Define how the ODEs should be integrated.\n+\n+Of the above, the NNPS algorithm is usually a well-known algorithm.  For\n+incompressible flows where the smoothing radius of the particles, :math:`h`,\n+is constant, a simple bin-based linked list implementation is standard.  For\n+cases where :math:`h` varies, a tree-based algorithm is typically used.  Users\n+usually do not need to experiment or modify the NNPS.  PySPH allows the rest\n+of the tasks to be all implemented in pure Python.\n+\n+\n+The PySPH framework\n+-------------------\n+\n+PySPH allows a user to specify the inter-particle interactions as well as the\n+ODE integration in pure Python with a rather simple and low-level syntax.\n+This is described in greater detail further below.  As discussed in the\n+introduction, with older versions of PySPH as discussed in\n+:cite:`PR-pysph-scipy-2010`, these interactions would all need to be written\n+in Cython.  This was not very easy or convenient.  It was also rather\n+limiting.\n+\n+The current version of PySPH supports the following:\n+\n+- Define a complete SPH simulation entirely in Python.\n+- High-performance code is generated from this high-level Python code\n+  automatically and called.  The performance of this code is comparable to\n+  hand-written FORTRAN solvers.\n+- PySPH can use OpenMP seamlessly.  Users do not need to modify their code at\n+  all to use this.  This works on Linux, OS X, and Windows, and\n+  produces good scale-up.\n+- PySPH also works with MPI and once again this is transparent to the user in\n+  that the user does not have to change code to use multiple machines.  This\n+  feature requires mpi4py_ and Zoltan_ to be installed.\n+- PySPH provides a built-in 3D viewer for the particle data generated.  The\n+  viewer requires Mayavi_ :cite:`it:mayavi:cise:gael2011` To be installed.\n+- PySPH is also free and currently hosted at http://pysph.bitbucket.org\n+\n+\n+In the following subsection we provide a high-level overview of PySPH and see\n+how it can be used by a user.  Subsequent subsections discuss the design and\n+implementation in greater detail.\n+\n+.. _mpi4py: http://mpi4py.scipy.org\n+.. _Zoltan: http://www.cs.sandia.gov/zoltan/\n+.. _Mayavi: http://code.enthought.com/projects/mayavi\n+\n+\n+\n+High-level overview\n+~~~~~~~~~~~~~~~~~~~\n+\n+PySPH is tested to work with Python-2.6.x to 2.7.x and also with Python\n+3.4/3.5.  PySPH is a typical Python package and can be installed fairly easily\n+by running::\n+\n+  $ pip install pysph\n+\n+PySPH will require a C++ compiler.  On Linux, this is trivial to get and\n+usually pre-installed.  On OS X, clang will work as will gcc (which can be\n+easily installed using brew_). On Windows the Visual C++ Compiler for Python\n+will need to be installed.  Detailed instructions for all these are available\n+from the `PySPH documentation`_.\n+\n+If one wishes to use OpenMP,\n+\n+- On Linux one needs to have libgomp installed.\n+- On OS X one needs to install OpenMP for clang or one could use GCC which\n+  supports OpenMP via brew_.\n+- On Windows, just having the Visual C++ computer for Python will work.\n+\n+If one wishes to use MPI for distributed computing, one must install Zoltan_\n+which is typically easy to install.  PySPH provides a simple script for this.\n+mpi4py_ is also needed in this case.  Unfortunately, MPI is not tested on\n+Windows by us currently.\n+\n+PySPH also provides an optional 3D viewer and this depends on Mayavi_.\n+\n+In summary, PySPH is easy to install if one has a C++ compiler installed.\n+MPI support is a little involved due to the requirement to install Zoltan_.\n+\n+.. _brew: http://brew.sh/\n+.. _PySPH Documentation: http://pysph.readthedocs.io\n+\n+\n+Once PySPH is installed an executable called ``pysph`` is available.  This is\n+a convenient entry point for various tasks.  Running ``pysph -h`` will provide\n+a listing of these possible tasks.  For example, the test suite can be run\n+using::\n+\n+  $ pysph test\n+\n+This uses nose_ internally and can be passed any arguments that ``nosetests``\n+accepts.\n+\n+PySPH installs about 30 useful examples along with the sources and any of\n+these examples can be readily run.  For example::\n+\n+  $ pysph run\n+  1. cavity\n+     Lid driven cavity using the Transport Velocity\n+     formulation. (10 minutes)\n+  2. couette\n+     Couette flow using the transport velocity\n+     formulation (30 seconds).\n+  [...]\n+  6. elliptical_drop\n+     Evolution of a circular patch of incompressible\n+     fluid. (60 seconds)\n+  [...]\n+  Enter example number you wish to run:\n+\n+\n+Will provide a listing of the examples prompting for a particular one to run.\n+Each example also provides a convenient time estimate if it were to be run in\n+serial.  The example number can be provided at the prompt.  If the name of the\n+example to run is known, one may directly specify it::\n+\n+  $ pysph run elliptical_drop\n+\n+This example will accept a large number of command line arguments.  To find\n+these one can run::\n+\n+  $ pysph run elliptical_drop -h\n+\n+``pysph run`` will execute the standard example.  Note that internally this is\n+somewhat equivalent to running::\n+\n+  $ python -m pysph.examples.elliptical_drop\n+\n+The example may therefore be imported in Python and also extended by users.\n+This is by design.\n+\n+When the example is run using ``pysph run``, the example documentation is\n+first printed and then the example is run.  The example will typically dump\n+the output of the computations to a directory called ``example_name_output``,\n+in the above case this would be ``elliptical_drop_output``.  This output can\n+be viewed using the Mayavi viewer.  This can be done using::\n+\n+  $ pysph view elliptical_drop_output\n+\n+This will start up the viewer with the saved files dumped in the directory.\n+Figure :ref:`fig:pysph-viewer` shows the viewer in action.  The viewer\n+provides a very convenient interface to view the data.  On the right side, one\n+has a standard Mayavi widget which also features a Mayavi icon on the toolbar.\n+Clicking this will open the Mayavi UI with which one can easily change the\n+visualization.  On the left pane there are three sub panels.  On the top, one\n+can see a slider for the file count. This can be used to move through the\n+simulation in time.  This can be also animated by checking the \"Play\" checkbox\n+which will iterate over the files.  The \"Directory\" button allows one to view\n+data from a different output directory.  Hitting the refresh button will\n+rescan the directory to check for any new files.  This makes it convenient to\n+visualize the results from a running simulation.  The \"Connection\" tab can be\n+used when the visualization is in \"Live mode\" when it can connect to a running\n+simulation and view the data live.  While this is very cool in principle, it\n+is seldom used in practice as it is a lot more efficient to just view the\n+dumped files and use the \"Refresh\" button is convenient.  Regardless, it does\n+show another feature of PySPH in that one can actually pause a running\n+simulation and query it if needed.  Below this pane is a \"Solver\" pane which\n+shows the various solver parameters of interest.  The \"Movie\" tab allows a\n+user to dump screenshots and easily produce a movie if needed.  At the bottom\n+of the interface are two panels called \"Particle arrays\" and \"Interpolator\".\n+The particle arrays lists all the particles and different scalar properties\n+associated with the SPH simulation.  Selecting different scalars will display\n+those scalars.  The interpolator tab allows a user to specify a rectilinear\n+region on which the particle properties may be interpolated and visualized --\n+for example if one wishes to see a contour of velocity magnitudes this would\n+be useful.  Right at the bottom is a button to launch a Python shell.  This\n+can be used for advanced scripting and is seldom used by beginners.  This\n+entire viewer is written using about 1024 lines of code and ships with PySPH.\n+\n+\n+.. figure:: mayavi_viewer.png\n+   :alt: Mayavi-based viewer bundled with PySPH.\n+\n+   The viewer provides a convenient interface to view data dumped by\n+   simulations. :label:`fig:pysph-viewer`\n+\n+\n+PySPH output can be dumped either in the form of ``.npz`` files (which are\n+generated by NumPy_) or HDF5 files if h5py_ is installed.  These files can be\n+viewed using other tools or with Python scripts if desired.  The HDF5 in\n+particular can be viewed more easily.  In addition, the ``pysph dump_vtk``\n+command can be used to dump VTK output files that can be used to visualize the\n+output using any tool that supports VTK files like ParaView etc.  This can use\n+either Mayavi or can use pyvisfile_ which has no dependency on VTK.  Finally,\n+the saved data files can be loaded in Python very easily, for example:\n+\n+.. code-block:: python\n+\n+    from pysph.solver.utils import load\n+    data = load('elliptical_drop_100.hdf5')\n+    # if one has only npz files the syntax is the same.\n+    data = load('elliptical_drop_100.npz')\n+\n+This provides a dictionary from which one can obtain the particle arrays and\n+solver data:\n+\n+.. code-block:: python\n+\n+    particle_arrays = data['arrays']\n+    solver_data = data['solver_data']\n+\n+``particle_arrays`` is a dictionary of all the PySPH particle arrays.\n+One can obtain the PySPH particle array, ``fluid``, like so:\n+\n+.. code-block:: python\n+\n+    fluid = particle_arrays['fluid']\n+    p = fluid.p\n+\n+Here ``p`` is a NumPy array of the pressure of each particle.  Particle arrays\n+are described in greater detail in the following sections.  Our intention here\n+is to show that the dumped data can be very easily loaded back into Python if\n+desired.\n+\n+\n+.. _nose: https://pypi.python.org/pypi/nose\n+.. _NumPy: http://numpy.scipy.org\n+.. _h5py: http://www.h5py.org\n+.. _pyvisfile: http://mathema.tician.de/software/pyvisfile\n+\n+\n+As discussed earlier, PySPH supports OpenMP and MPI.  To use multiple cores on\n+a computer one can simply run an example or script as::\n+\n+  $ pysph run elliptical_drop --openmp\n+\n+This will use OpenMP transparently and should work for all the PySPH\n+examples.  PySPH will honor the ``OMP_NUM_THREADS`` environment variable to\n+pick the number of threads.  If PySPH is installed with MPI support through\n+Zoltan, then one may run for example::\n+\n+  $ mpirun -np 4 pysph run dam_break_3d\n+\n+This will run the ``dam_break_3d`` example with 4 processors.  The amount of\n+scale-up depends on the size of the problem and the network.  OpenMP will\n+scale fairly well for moderately sized problems.  Note that for a general\n+PySPH script written by the user, the command to run would simply be::\n+\n+  $ mpirun -np 4 python my_script.py\n+\n+Similarly when using OpenMP::\n+\n+  $ python my_example.py --openmp\n+\n+This provides a very high-level introduction to PySPH in general.  The next\n+section discusses some essential software engineering used in the development\n+of PySPH.  This is followed by details on the underlying design of PySPH.","path":"papers/prabhu_ramachandran_pysph/prabhu_ramachandran_pysph.rst","position":503,"original_position":503,"commit_id":"ad2e351d2000e5501bdeab3bb0fbae9f28097fce","original_commit_id":"64c1d9c255f82cca1bb2b932f4994d0e9e666fdd","user":{"login":"prabhuramachandran","id":272585,"avatar_url":"https://avatars.githubusercontent.com/u/272585?v=3","gravatar_id":"","url":"https://api.github.com/users/prabhuramachandran","html_url":"https://github.com/prabhuramachandran","followers_url":"https://api.github.com/users/prabhuramachandran/followers","following_url":"https://api.github.com/users/prabhuramachandran/following{/other_user}","gists_url":"https://api.github.com/users/prabhuramachandran/gists{/gist_id}","starred_url":"https://api.github.com/users/prabhuramachandran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prabhuramachandran/subscriptions","organizations_url":"https://api.github.com/users/prabhuramachandran/orgs","repos_url":"https://api.github.com/users/prabhuramachandran/repos","events_url":"https://api.github.com/users/prabhuramachandran/events{/privacy}","received_events_url":"https://api.github.com/users/prabhuramachandran/received_events","type":"User","site_admin":false},"body":"I have not really addressed this as there is a roadmap at the beginning of the section.  This particular overview was rather long so I put the roadmap here again so it reads nicely.  I am happy to make more changes if you feel that it helps.","created_at":"2016-06-19T21:01:49Z","updated_at":"2016-06-19T21:01:49Z","html_url":"https://github.com/scipy-conference/scipy_proceedings/pull/214#discussion_r67623783","pull_request_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214","_links":{"self":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments/67623783"},"html":{"href":"https://github.com/scipy-conference/scipy_proceedings/pull/214#discussion_r67623783"},"pull_request":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214"}}},"pull_request":{"url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214","id":71969786,"html_url":"https://github.com/scipy-conference/scipy_proceedings/pull/214","diff_url":"https://github.com/scipy-conference/scipy_proceedings/pull/214.diff","patch_url":"https://github.com/scipy-conference/scipy_proceedings/pull/214.patch","issue_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/214","number":214,"state":"open","locked":false,"title":"Paper: PySPH. Prabhu Ramachandran","user":{"login":"prabhuramachandran","id":272585,"avatar_url":"https://avatars.githubusercontent.com/u/272585?v=3","gravatar_id":"","url":"https://api.github.com/users/prabhuramachandran","html_url":"https://github.com/prabhuramachandran","followers_url":"https://api.github.com/users/prabhuramachandran/followers","following_url":"https://api.github.com/users/prabhuramachandran/following{/other_user}","gists_url":"https://api.github.com/users/prabhuramachandran/gists{/gist_id}","starred_url":"https://api.github.com/users/prabhuramachandran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prabhuramachandran/subscriptions","organizations_url":"https://api.github.com/users/prabhuramachandran/orgs","repos_url":"https://api.github.com/users/prabhuramachandran/repos","events_url":"https://api.github.com/users/prabhuramachandran/events{/privacy}","received_events_url":"https://api.github.com/users/prabhuramachandran/received_events","type":"User","site_admin":false},"body":"The paper is now complete in terms of content.  I will revise it over the course of the week.","created_at":"2016-05-31T07:31:57Z","updated_at":"2016-06-19T21:01:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"20e9c546118f121f6b16c82f623f298a6dc2402c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214/commits","review_comments_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214/comments","review_comment_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments{/number}","comments_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/214/comments","statuses_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/statuses/ad2e351d2000e5501bdeab3bb0fbae9f28097fce","head":{"label":"prabhuramachandran:2016_paper2","ref":"2016_paper2","sha":"ad2e351d2000e5501bdeab3bb0fbae9f28097fce","user":{"login":"prabhuramachandran","id":272585,"avatar_url":"https://avatars.githubusercontent.com/u/272585?v=3","gravatar_id":"","url":"https://api.github.com/users/prabhuramachandran","html_url":"https://github.com/prabhuramachandran","followers_url":"https://api.github.com/users/prabhuramachandran/followers","following_url":"https://api.github.com/users/prabhuramachandran/following{/other_user}","gists_url":"https://api.github.com/users/prabhuramachandran/gists{/gist_id}","starred_url":"https://api.github.com/users/prabhuramachandran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prabhuramachandran/subscriptions","organizations_url":"https://api.github.com/users/prabhuramachandran/orgs","repos_url":"https://api.github.com/users/prabhuramachandran/repos","events_url":"https://api.github.com/users/prabhuramachandran/events{/privacy}","received_events_url":"https://api.github.com/users/prabhuramachandran/received_events","type":"User","site_admin":false},"repo":{"id":20846741,"name":"scipy_proceedings","full_name":"prabhuramachandran/scipy_proceedings","owner":{"login":"prabhuramachandran","id":272585,"avatar_url":"https://avatars.githubusercontent.com/u/272585?v=3","gravatar_id":"","url":"https://api.github.com/users/prabhuramachandran","html_url":"https://github.com/prabhuramachandran","followers_url":"https://api.github.com/users/prabhuramachandran/followers","following_url":"https://api.github.com/users/prabhuramachandran/following{/other_user}","gists_url":"https://api.github.com/users/prabhuramachandran/gists{/gist_id}","starred_url":"https://api.github.com/users/prabhuramachandran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prabhuramachandran/subscriptions","organizations_url":"https://api.github.com/users/prabhuramachandran/orgs","repos_url":"https://api.github.com/users/prabhuramachandran/repos","events_url":"https://api.github.com/users/prabhuramachandran/events{/privacy}","received_events_url":"https://api.github.com/users/prabhuramachandran/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/prabhuramachandran/scipy_proceedings","description":"Tools used to generate the SciPy conference proceedings","fork":true,"url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings","forks_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/forks","keys_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/keys{/key_id}","collaborators_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/teams","hooks_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/hooks","issue_events_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/issues/events{/number}","events_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/events","assignees_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/assignees{/user}","branches_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/branches{/branch}","tags_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/tags","blobs_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/git/refs{/sha}","trees_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/git/trees{/sha}","statuses_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/statuses/{sha}","languages_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/languages","stargazers_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/stargazers","contributors_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/contributors","subscribers_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/subscribers","subscription_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/subscription","commits_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/commits{/sha}","git_commits_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/git/commits{/sha}","comments_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/comments{/number}","issue_comment_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/issues/comments{/number}","contents_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/contents/{+path}","compare_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/compare/{base}...{head}","merges_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/merges","archive_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/downloads","issues_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/issues{/number}","pulls_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/pulls{/number}","milestones_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/milestones{/number}","notifications_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/labels{/name}","releases_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/releases{/id}","deployments_url":"https://api.github.com/repos/prabhuramachandran/scipy_proceedings/deployments","created_at":"2014-06-15T02:50:13Z","updated_at":"2016-05-28T18:40:50Z","pushed_at":"2016-06-19T20:58:01Z","git_url":"git://github.com/prabhuramachandran/scipy_proceedings.git","ssh_url":"git@github.com:prabhuramachandran/scipy_proceedings.git","clone_url":"https://github.com/prabhuramachandran/scipy_proceedings.git","svn_url":"https://github.com/prabhuramachandran/scipy_proceedings","homepage":"","size":5416,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"scipy-conference:2016","ref":"2016","sha":"c91d1c88fe313a4503f92413cbdc879ecddf223a","user":{"login":"scipy-conference","id":4884274,"avatar_url":"https://avatars.githubusercontent.com/u/4884274?v=3","gravatar_id":"","url":"https://api.github.com/users/scipy-conference","html_url":"https://github.com/scipy-conference","followers_url":"https://api.github.com/users/scipy-conference/followers","following_url":"https://api.github.com/users/scipy-conference/following{/other_user}","gists_url":"https://api.github.com/users/scipy-conference/gists{/gist_id}","starred_url":"https://api.github.com/users/scipy-conference/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scipy-conference/subscriptions","organizations_url":"https://api.github.com/users/scipy-conference/orgs","repos_url":"https://api.github.com/users/scipy-conference/repos","events_url":"https://api.github.com/users/scipy-conference/events{/privacy}","received_events_url":"https://api.github.com/users/scipy-conference/received_events","type":"Organization","site_admin":false},"repo":{"id":1825629,"name":"scipy_proceedings","full_name":"scipy-conference/scipy_proceedings","owner":{"login":"scipy-conference","id":4884274,"avatar_url":"https://avatars.githubusercontent.com/u/4884274?v=3","gravatar_id":"","url":"https://api.github.com/users/scipy-conference","html_url":"https://github.com/scipy-conference","followers_url":"https://api.github.com/users/scipy-conference/followers","following_url":"https://api.github.com/users/scipy-conference/following{/other_user}","gists_url":"https://api.github.com/users/scipy-conference/gists{/gist_id}","starred_url":"https://api.github.com/users/scipy-conference/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scipy-conference/subscriptions","organizations_url":"https://api.github.com/users/scipy-conference/orgs","repos_url":"https://api.github.com/users/scipy-conference/repos","events_url":"https://api.github.com/users/scipy-conference/events{/privacy}","received_events_url":"https://api.github.com/users/scipy-conference/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/scipy-conference/scipy_proceedings","description":"Tools used to generate the SciPy conference proceedings","fork":false,"url":"https://api.github.com/repos/scipy-conference/scipy_proceedings","forks_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/forks","keys_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/keys{/key_id}","collaborators_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/teams","hooks_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/hooks","issue_events_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/events{/number}","events_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/events","assignees_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/assignees{/user}","branches_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/branches{/branch}","tags_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/tags","blobs_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/refs{/sha}","trees_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/trees{/sha}","statuses_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/statuses/{sha}","languages_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/languages","stargazers_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/stargazers","contributors_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/contributors","subscribers_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/subscribers","subscription_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/subscription","commits_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/commits{/sha}","git_commits_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/git/commits{/sha}","comments_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/comments{/number}","issue_comment_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/comments{/number}","contents_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/contents/{+path}","compare_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/compare/{base}...{head}","merges_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/merges","archive_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/downloads","issues_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues{/number}","pulls_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls{/number}","milestones_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/milestones{/number}","notifications_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/labels{/name}","releases_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/releases{/id}","deployments_url":"https://api.github.com/repos/scipy-conference/scipy_proceedings/deployments","created_at":"2011-05-31T10:26:48Z","updated_at":"2016-05-14T13:06:42Z","pushed_at":"2016-06-19T20:58:02Z","git_url":"git://github.com/scipy-conference/scipy_proceedings.git","ssh_url":"git@github.com:scipy-conference/scipy_proceedings.git","clone_url":"https://github.com/scipy-conference/scipy_proceedings.git","svn_url":"https://github.com/scipy-conference/scipy_proceedings","homepage":"","size":165726,"stargazers_count":87,"watchers_count":87,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":171,"mirror_url":null,"open_issues_count":26,"forks":171,"open_issues":26,"watchers":87,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214"},"html":{"href":"https://github.com/scipy-conference/scipy_proceedings/pull/214"},"issue":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/214"},"comments":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/issues/214/comments"},"review_comments":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214/comments"},"review_comment":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/pulls/214/commits"},"statuses":{"href":"https://api.github.com/repos/scipy-conference/scipy_proceedings/statuses/ad2e351d2000e5501bdeab3bb0fbae9f28097fce"}}}}
{"actor":{"display_login":"prabhuramachandran"}}