Commit 4ef82f83 authored by Emilia Juda's avatar Emilia Juda

migrated content from interim report and markdown files

parent 32370a4f
\subsection{Documentation}
The NekPy package certainly had to be documented in order to provide an easily accessible information about the wrapped classes to both users and developers. Ideally, the documentation should be:
\begin{itemize}
\item easily readable by humans,
\item accessible using Python's inbuilt \texttt{help} method,
\item compatible with the existing Nektar++ doxygen-based documentation.
\end{itemize}
Traditionally, Python classes and functions are documented using a docstring -- a string occurring as the very first statement after the function or class is defined. This string is then accessible as the \texttt{\_\_doc\_\_} attribute of the function or class. The conventions associated with Python docstrings are described in PEP 257 document \cite{PEP257}.
Boost.Python provides an easy way to include docstrings in the wrapped methods and classes as shown in Listing \ref{lst:doc_example}. The included docstrings will appear when Python \texttt{help} method is used.
\begin{lstlisting}[caption={Example of class and method documentation in Boost.Python}, label={lst:doc_example}, language=C++]
void export_Points()
{
py::class_<PointsKey>("PointsKey",
"Create a PointsKey which uniquely defines quadrature points.\n"
"\n"
"Args:\n"
"\tnQuadPoints (integer): The number of quadrature points.\n"
"\tpointsType (PointsType object): The type of quadrature points.",
py::init<const int, const PointsType&>())
.def("GetNumPoints", &PointsKey::GetNumPoints,
"Get the number of quadrature points in PointsKey.\n"
"\n"
"Args:\n"
"\tNone\n"
"Returns:\n"
"\tInteger defining the number of quadrature points in PointsKey.")
}
\end{lstlisting}
In order to fully document the existing bindings a number of enumeration type classes such as \texttt{PointsType} had to have docstrings included which proved to be a challenge since Boost.Python does not provide a way to do this. Instead a direct call to Python C API has to be made and the method adapted from \cite{python_enum_docstring} was used, as shown in Listing \ref{lst:enum_doc}. A downside of this solution is that it does requires the developer to manually update the Python documentation if the enumeration type is ever changed (e.g. adding a new type of point) as the code does not automatically gather information from the C++ class. In theory it could be possible to create a Python script which would generate Python docstrings based on the existing C++ documentation using regular expressions; however it would be difficult to integrate this solution into the existing framework.
\begin{lstlisting}[caption={Code used to include dosctings in enumetation type classes - part of \texttt{NekPyConfig.hpp}}, label={lst:enum_doc}, language=C++]
#define NEKPY_WRAP_ENUM_STRING_DOCS(ENUMNAME,MAPNAME,DOCSTRING) \
{ \
py::enum_<ENUMNAME> tmp(#ENUMNAME); \
for (int a = 0; a < (int)SIZENAME(ENUMNAME); ++a) \
{ \
tmp.value(MAPNAME[a].c_str(), (ENUMNAME)a); \
} \
tmp.export_values(); \
PyTypeObject * pto = \
reinterpret_cast<PyTypeObject*>(tmp.ptr()); \
PyDict_SetItemString(pto->tp_dict, "__doc__", \
PyString_FromString(DOCSTRING)); \
}
\end{lstlisting}
There are many docstrings conventions that are popular in Python such as Epytext, reST and Google therefore a choice had to be made as to which docstring style to use. After considering the criteria which the documentation had to fulfill it was decided to use Google Python Style \cite{python_google} as it is highly readable by humans (and hence an excellent choice for documentation which will be primarily accessible by Python \texttt{help} method) and can be used to generate automated documentation pages with Sphinx (a tool for creating Python documentation).
Unfortunately, it proved to be difficult to include the documentation of NumPy package in the existing doxygen-based documentation due to the fact that the docstrings are generated by Boost.Python. It was decided that if the time constraints of the project permit this problem could be resolved at a later date and the possibility of accessing the documentation though inbuilt \texttt{help} method was deemed sufficient.
\section{Installing NekPy}
NekPy has the following list of requirements:
\begin{itemize}
\item Boost with Python support
\item Nektar++ \texttt{master} branch compiled from source (i.e. not from packages)
\item Python 2.7+ (note that examples rely on Python 2.7)
\item NumPy
\end{itemize}
Most of these can be installed using package managers on various operating
systems, as we describe below. We also have a requirement on the \texttt{Boost.NumPy}
package, which is available in Boost 1.63 or later. If this isn't found on your
system, it will be automatically downloaded and compiled.
\subsection{Compiling and installing Nektar++}
Nektar++ should be compiled as per the user guide instructions and installed
into a directory which we will refer to as \texttt{$NEKDIR}. By default this is the
\texttt{dist} directory inside the Nektar++ build directory.
Note that Nektar++ must, at a minimum, be compiled with \texttt{NEKTAR_BUILD_LIBRARY},
\texttt{NEKTAR_BUILD_UTILITIES} , \texttt{NEKTAR_BUILD_SOLVERS} and \texttt{NEKTAR_BUILD_PYTHON}.
This will automatically download and install \texttt{Boost.NumPy} if required. Note
that all solvers may be disabled as long as the \texttt{NEKTAR_BUILD_SOLVERS} option is set.
\subsubsection{macOS}
\paragraph{Homebrew}
Users of Homebrew should make sure their installation is up-to-date with
\texttt{brew upgrade}. Then run
\begin{lstlisting}[language=bash]
brew install python boost-python
\end{lstlisting}
To install the NumPy package, use the \texttt{pip} package manager:
\begin{lstlisting}[language=bash]
pip install numpy
\end{lstlisting}
\paragraph{MacPorts}
Users of MacPorts should sure their installation is up-to-date with
\texttt{sudo port selfupdate && sudo port upgrade outdated}. Then run
\begin{lstlisting}[language=bash]
sudo port install python27 py27-numpy
sudo port select --set python python27
\end{lstlisting}
\subsubsection{Linux: Ubuntu/Debian}
Users of Debian and Ubuntu Linux systems should sure their installation is
up-to-date with \texttt{sudo apt-get update && sudo apt-get upgrade}
\begin{lstlisting}[language=bash]
sudo apt-get install libboost-python-dev python-numpy
\end{lstlisting}
\subsubsection{Compiling the wrappers}
Run the following command in \texttt{$NEKDIR\build} directory to install the Python package
for the current user:
\begin{lstlisting}[language=bash]
make nekpy-install-user
\end{lstlisting}
Alternatively, the following command can be used to install the package for all users:
\begin{lstlisting}[language=bash]
make nekpy-install-system
\end{lstlisting}
\subsection{Using the bindings}
By default, the bindings will install into the \texttt{dist} directory, along with a
number of examples that are stored in the \texttt{$NEKDIR\library\Demos\Python} directory. To
test your installation, you can for example run one of these (e.g. \texttt{python Basis.py}) or
launch an interactive session:
\begin{lstlisting}[language=bash]
$ cd builds
$ python
Python 2.7.13 (default, Apr 4 2017, 08:47:57)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from NekPy.LibUtilities import PointsKey, PointsType
>>> PointsKey(10, PointsType.GaussLobattoLegendre)
<NekPy.LibUtilities._LibUtilities.PointsKey object at 0x11005c310>
\end{lstlisting}
\subsubsection{Examples}
A number of examples of the wrappers can be found in the \texttt{$NEKDIR\library\Demos\Python}
directory, along with a sample mesh \texttt{newsquare_2x2.xml}:
\begin{itemize}
\item \texttt{SessionReader.py} is the simplest example and shows how to construct a
session reader object. Run it as \texttt{python SessionReader.py mesh.xml}.
\item \texttt{Basis.py} shows functionality of basic \texttt{LibUtilities} points and basis
classes. Run this as \texttt{python Basis.py}.
\item \texttt{StdProject.py} shows how to use some of the \texttt{StdRegions} wrappers and
duplicates the functionality of \texttt{Basis.py} using the \texttt{StdExpansion} class. Run
this as \texttt{python StdProject.py}.
\item \texttt{MeshGraph.py} loads a mesh and prints out some basic properties of its
quadrilateral elements. Run it as \texttt{python MeshGraph.py newsquare_2x2.xml}.
\end{itemize}
If you want to modify the source files, it's advisable to edit them in the
\texttt{$NEKDIR\library\Demos\Python} directory and re-run \texttt{make install}, otherwise local
changes will be overwritten by the next \texttt{make install}.
\section{Introduction}
This repository contains the \texttt{NekPy} Python wrappers for the Nektar++
spectral/\textit{hp} element framework. \emph{As a disclaimer, these wrappings are
experimental and incomplete.} You should not rely on their current
structure and API remaining unchanged.
Currently, representative classes from the \texttt{LibUtilities}, \texttt{StdRegions},
\texttt{SpatialDomains} and \texttt{LocalRegions} libraries have been wrapped in order to show
the proof-of-concept.
\subsection{Features and functionality}
\texttt{NekPy} uses the \texttt{Boost.Python} library to provide a set of high-quality,
hand-written Python bindings for selected functions and classes in Nektar++. A
typical snippet could look something like:
\begin{lstlisting}[caption={NekPy sample snippet}, label={lst:nekpy_sample}, language=Python]
from NekPy.LibUtilities import PointsKey, PointsType, BasisKey, BasisType
from NekPy.StdRegions import StdQuadExp
import numpy as np
numModes = 8
numPts = 9
ptsKey = PointsKey(numPts, PointsType.GaussLobattoLegendre)
basisKey = BasisKey(BasisType.Modified_A, numModes, ptsKey)
quadExp = StdQuadExp(basisKey, basisKey)
x, y = quadExp.GetCoords()
fx = np.sin(x) * np.cos(y)
proj = quadExp.FwdTrans(fx)
\end{lstlisting}
\texttt{NekPy} uses the \texttt{Boost.NumPy} library, contained in Boost 1.63+, to
automatically convert C++ \texttt{Array<OneD, >} objects to and from the commonly-used
\texttt{numpy.ndarray} object, which makes the integration more seamless between Python
and C++.
\ No newline at end of file
This diff is collapsed.
The NekPy wrapper is designed to mimic the library structure of Nektar++, with
directories for the \texttt{LibUtilities}, \texttt{SpatialDomains} and \texttt{StdRegions}
libraries. This is a deliberate design decision, so that classes and definitions
in Nektar++ can be easily located inside NekPy.
There are also some other directories and files:
\begin{itemize}
\item \texttt{NekPyConfig.hpp} is a convenience header that all \texttt{.cpp} files should
import. It sets appropriate namespaces for \texttt{boost::python} and
\texttt{boost::python::numpy}, depending on whether the \texttt{Boost.NumPy} library was
compiled or is included in Boost.
\item \texttt{cmake} has some CMake configuration files.
\end{itemize}
\subsubsection{Package structure}
\label{sec:package_str}
Since the Python wrapper files have been moved to the main Nektar++ codebase as opposed to being contained in a separate repository, the structure of the package had to be modified. As suggested in \cite{thesis_spooner}, the namespaces of the NekPy package follow the namespaces of Nektar++ main codebase -- this is reflected both in the filenames as well as package modules (e.g. \texttt{NekPy.LibUtilities} module contains bindings of classess and methods found in \texttt{LibUtilities} library of Nektar++).
Figure \ref{fig:package_str} shows the location of Python wrapper files within Nektar++ structure. Every sub-module of Nektar++ hosts an additional folder for Python files and the structure of the Python folder mimics the structure of the sub-module itself, as shown on the left of the figure with \texttt{LibUtilities} sub-module. Individual \texttt{.cpp} files, such as \texttt{Expansion.cpp} contain the wrappers for classes and methods from corresponding Nektar++ library files whereas \texttt{.cpp} files named after sub-modules (e.g. \texttt{LibUtilities.cpp}) contain \texttt{BOOST\_PYTHON\_MODULE} definitions which create package modules (e.g. \texttt{NekPy.LibUtilities}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.9\textwidth]{package_str}
\caption{The location of Python wrapper files within Nektar++ structure.}
\label{fig:package_str}
\end{figure}
\ No newline at end of file
This diff is collapsed.
......@@ -448,4 +448,25 @@ year = "2012"
year = "2015",
url = "https://wiki.python.org/moin/boost.python/HowTo",
note = "[Accessed 1st May 2018]"
}
@misc{GitHubExamples,
title = "GitHub - TNG/boost-python-examples: Some examples for the use of boost::python",
year = "2016",
url = "https://github.com/TNG/boost-python-examples",
note = "[Accessed 7th May 2018]"
}
@misc{OpenStreetGraphCookbook,
title = "osgboostpython/WrappingCookbook.md at wiki · Skylark13/osgboostpython · GitHub",
year = "2015",
url = "https://github.com/Skylark13/osgboostpython/blob/wiki/WrappingCookbook.md",
note = "[Accessed 7th May 2018]"
}
@misc{ManualWrappingRationale,
title = "osgboostpython/ManualWrappingRationale.md at wiki · Skylark13/osgboostpython · GitHub",
year = "2015",
url = "https://github.com/Skylark13/osgboostpython/blob/wiki/ManualWrappingRationale.md",
note = "[Accessed 7th May 2018]"
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment