Click Here to Access the Github Repo
This is the repository for our final project for the discpline COMSW4995: Design in C++ at Columbia University during the Fall of 2022.
This project aims to implement in modern C++ a wave equation solver for geophysical application.
In addition, a custom implementation of numpy in modern C++ is also included as a header library. That library aims to make c++ more pythonic and easier to use for scientific computing. Instead of numpy n-dimensional arrays the library use boost::multi_array and contains many utilities to expand the functionality of the library.
Victor Barros - Undergradute Student - Mechanical Engineering - Columbia University
Yan Cheng - PhD Candidate - Applied Mathematics - Columbia University
We would like to thank Professor Bjarne Stroustrup for his guidance and support during the development of this project.
When waves travel in an inhomogeneous medium, they may be delayed, reflected, and refracted, and the wave data encodes information about the medium—this is what makes geophysical imaging possible. The propagation of waves in a medium is described by a partial differential equation known as the wave equation. In two dimension, the wave equation is given by:
In our simulation, the numerical scheme we use is the finite difference method with the perfectly matched layers [1]:
[1] Johnson, Steven G. (2021). Notes on perfectly matched layers (PMLs). arXiv preprint arXiv:2108.05348.
We have noticed that many users are very familiar with python and use it extensively with libraries such as numpy and scipy. However their code is often slow and not very low-level friendly. Even with numpy and scipy's low-level optimizations, there could still be margin for improvement by converting everything to C++, which would allow users to unleash even more optimizations and exert more control over how their code runs. This could also allow the code to run on less powerful devices that often don't support python.
With that in mind we decided to find a way to make transferring that numpy, scipy, etc code to C++ in an easy way, while keeping all of the high level luxuries of python. We decided to implement a numpy-like library in C++ that would allow users to write code in a similar way to python, but with the performance of C++.
We started with the implementation of the functions used in the python version of the wave solver and plan to expand the library to include more functions and features in the future.
The library is contained in a header library format for easy of use.
Representing arrays with more than one dimensions is a difficult task in any programming language, specially in a language like C++ that implements strict type checking. To implement that in a flexible and typesafe way, we chose to build our code around the boost::multi_array. This library provides a container that can be used to represent arrays with any number of dimensions. The library is very flexible and allows the user to define the type of the array and the number of dimensions at compile time. The library is sadly not very well documented but the documentation can be found here: https://www.boost.org/doc/libs/1_75_0/libs/multi_array/doc/index.html
We decided to build the math functions in a pythonic way, so we implemented numpy functions into our C++ library in a way that they would accept n-dimensions through a template parameters and act accordingly while enforcing dimensional conistency at compile time. We also used concepts and other modern C++ concepts to make sure that, for example, a python call such as np.max(my_n_dimensional_array) would be translated to np::max(my_n_dimensional_array) in C++.
To perform operations on an n-dimensional array we choose to iterate over it and convert the pointers to indexes using a simple arithmetic operation with one division. This is somewhat time consuming since we don't have O(1) time access to any point in the array, instead having O(n) where n is the amount of elements in the multi array. This is the tradeoff necessary to have n-dimensions represented in memory, hopefully in modern cpus this overhead won't be too high. Better solutions could be investigated further.
We also implemented simple arithmetic operators with multi arrays to make them more arithmetic friendly such as they are in python.
Only one small subset of numpy functions were implemented, but the library is easily extensible and more functions can be added in the future.
Please be aware that since this library uses a few C++ 20 features it is only been tested on gcc-11 and above. It is possible that it will work on other compilers but it is not guaranteed.
It is important to install the boost library before building the project. The boost library is used for data structures and algorithms. The boost library can be installed using the following command on ubuntu:
sudo apt-get install libboost-all-dev
For Mac:
brew install boost
This is the library used to generate graphics in the project. To be able to compile this project you must have it installed in your system. First install its dependencies:
sudo apt-get install gnuplot
or in Mac:
brew install gnuplot
Then install the library itself by cloning from source:
cd src/ExternalLibraries
git clone https://github.com/alandefreitas/matplotplusplus
cd matplotplusplu
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O2" -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF
sudo cmake --build . --parallel 2 --config Release
sudo cmake --install .
If you are using clang on mac, make sure to force CMAKE to use gcc by adding the following flag to the first cmake command:
-DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++
(or equivalent paths depending on where your gcc is installed)
mkdir build
cd build
cmake ..
make all
You can also build only the executable by running:
make WaveSimPPExec
./WaveSimPPExec
Use the help flag -h to see the available runtime options and the full list and description of the parameters.
Docs building script:
./compileDocs.sh
Manually:
doxygen dconfig
cd documentation/latex
pdflatex refman.tex
cp refman.pdf ../WaveSimPP-1.0-doc.pdf