Slide 1

Slide 1 text

INTRODUCTION TO C++ PART II ROHIT GOSWAMI MINSTP Created: 2021-04-13 Tue 04:58 1

Slide 2

Slide 2 text

1 BRIEF INTRODUCTION 2 . 1

Slide 3

Slide 3 text

1.1 HELLO! Find me here: Who? Rohit Goswami MInstP Doctoral Researcher, University of Iceland, Faculty of Physical Sciences https://rgoswami.me 2 . 2

Slide 4

Slide 4 text

1.2 LOGISTICS All contents are Slides are in docs/pres hosted on GitHub Slides have shortned commit IDs These lead to speci c points in the git log Questions are welcome after / during the lecture have been set up for this GitHub Discussions 2 . 3

Slide 5

Slide 5 text

2 LOCAL PROJECT LAYOUTS 3 . 1

Slide 6

Slide 6 text

2.1 LANGUAGE AGNOSTIC BEGINNINGS Readme.{md,org} Motivation, rationale, license, installation instructions LICENSE Plain text, and preferably an open license is pretty handy for this license-generator .gitignore Lists les which do not need to be committed; typically generated les can be used to generate these gibo $ git init # Inside project $ gibo macOS Windows Xcode Emacs \ Vim Python C \ CMake TeX > .gitignore $ touch readme.md $ license-generator MIT \ author "Person" $ tree -L 2 . ├── LICENSE ├── docs │ └── pres └── readme.org 2 directories, 2 files sha256:9c29414 3 . 2

Slide 7

Slide 7 text

2.2 C++ PROJECT STRUCTURE src/ Should be split into libraries and executables include/ For headers, internal and external docs/ Documentation of all kinds, typically including markdown les CMakeLists.txt The project build system ci/ Scripts for continuous integration 1 Along each -I and INCLUDE #include Starts in the same directory Reverse order upward -I and INCLUDE #include "path-spec" sha256:a5a0a9e 3 . 3

Slide 8

Slide 8 text

3 ITERATIVE IMPROVEMENTS - I 4 . 1

Slide 9

Slide 9 text

Comments are imperative Segregation of build allows for easy cleanup rm -rf build 3.1 REFACTORING CMAKEFILE - I # Variables if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release endif() set(CMAKE_CXX_FLAGS "-Wall -Wextra") set(CMAKE_CXX_FLAGS_DEBUG "-g") set(CMAKE_CXX_FLAGS_RELEASE "-O3") $ # Should fail!!! $ cmake . sha256:8193ad9 cmake_minimum_required(VERSION 3.14 FA # ---- Project ---- project( PenningTrapSimulationII VERSION 1.0 LANGUAGES CXX ) # ---- Include guards ---- if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there." ) endif() $ # Works $ cmake -H. -Bbuild $ cmake build build $ cd build $ simulation.exe 4 . 2

Slide 10

Slide 10 text

3.2 HEADER ONLY INCLUDES These are meant for small classes With inlined de nitions #ifndef IOP_VEC_H #define IOP_VEC_H #endif IOP_VEC_H Prevents multiple inclusion Modularity means more unit-tests Better guarantees # Library set(headers "${CMAKE_CURRENT_SOURCE_DIR}/include set(sources "${CMAKE_CURRENT_SOURCE_DI # Build add_executable(simulation.exe ${source # Add to INCLUDE target_include_directories( simulation.exe PUBLIC $ to "" for includes #include sha256:9ca7f3a 4 . 3

Slide 11

Slide 11 text

3.3 NAMESPACES Further improves modularity Fewer clashes Never use using namespace iopdat { data_types/iop_particle.hpp class Particle { public: Vector3 position; } } Same conceptual region, even across les namespace iopdat { data_types/iop_vec.hpp class Vector3 { } } set(headers "include/data_types/iop_vec.hpp" "include/data_types/iop_particle.hpp ) #include #include Regrouped the data_types math_types wasn’t primitive enough Refactoring early is normal With tests sha256:2f1b161 4 . 4

Slide 12

Slide 12 text

Before After 3.4 COMPILED LIBRARIES class TimeStepper { private: std vector physics_list; iopdat Particle p; double dt; public: TimeStepper(double time_step_size, double charge, double mass) : p(charge, mass) { dt = time_step_size; } }; class TimeStepper { private: std vector physic iopdat Particle p; double dt; public: TimeStepper(double time_step_size, double charge, double mass); void AddProcess(PhysicsProcess* process); void Setup(iopdat Vector3 position, iopdat Vector3 Velocity) void Step(); void Print(); }; 4 . 5

Slide 13

Slide 13 text

Header Only Compiled 3.4.1 WHY? Easier to install Can be dropped in and versioned Slow, especially installed They are expanded Compiled code is faster Adds complexity though Needs a build system Can easier to read More modular Easier to document $ tree -L . . ├── CMakeLists.txt ├── LICENSE ├── docs │ └── pres ├── include │ ├── data_types │ └── phys_procs.hpp ├── libsrc │ └── phys_procs.cpp ├── readme.org └── src ├── CMakeLists.txt └── main.cpp 6 directories, 7 files 4 . 6

Slide 14

Slide 14 text

3.4.2 HOW? - I CODE SEPARATION declared in .hpp /** * @brief Takes a step * @returns None. void Step(); The build system takes on most of the debt Compiles the code as a library “header-only” libraries can also be built Ensures it can be linked at runtime de ned in .cpp /** * @detail The algorithm is a direct * of standard mechanics void physproc TimeStepper Step() { iopdat Vector3 F(0, 0, 0); for (int i = 0; i < physics_list.size(); i ) { F += physics_list.at(i) Force(p); } iopdat Vector3 dv(dt * F.x / p.mass, dt * F.y / p.mass, dt * F.z / p.mass) p.velocity += dv; p.position += iopdat Vector3(p.velocity.x * dt, p.velocity.y * dt, p.velocity.z * dt) } 4 . 7

Slide 15

Slide 15 text

3.4.3 HOW? - II BUILDING AND LINKING For header-only libraries PUBLIC -> INTERFACE target: add_library(ioplib INTERFACE) main.cpp #include sha256:e6d048e # Build order add_dependencies(simulation.exe ioplib # Libraries target_link_libraries(simulation.exe ioplib) # Dependencies add_library( ioplib SHARED "libsrc/phys_procs.cpp" ) # Still need the older headers target_include_directories( ioplib PUBLIC $ ) 4 . 8

Slide 16

Slide 16 text

3.4.4 WHEN? Larger projects refactor often Modular components make it easy for new contributors Reuse of code is easier this way The speed bene ts can be considerable Speed here means compilation time boost is a classic example of a mostly compiled library Eigen3 is famously header-only Let there be libraries!! — Rohit Goswami (2021) 4 . 9

Slide 17

Slide 17 text

4 PACKAGE MANAGEMENT 5 . 1

Slide 18

Slide 18 text

4.1 CURRENT SCENARIO 2 Nix is the answer!! (not here) Python poetry, pipenv, pyenv C++ conan, vcpkg, cpm

Slide 19

Slide 19 text

5 . 2

Slide 20

Slide 20 text

4.2 CPM AND CMAKE mkdir -p cmake wget -O cmake/CPM.cmake "https github.com/cpm-cmake/\ CPM.cmake/releases/latest/download/get_cpm.cmake" # Can get slow otherwise, rebuilds constantly export CPM_SOURCE_CACHE=$HOME/.cache/CPM # Helpers include(cmake/CPM.cmake) CPMUsePackageLock(package-lock.cmake) # We like locks cmake -H. -Bbuild cmake build build target cpm-update-package-lock 5 . 3

Slide 21

Slide 21 text

5 TESTING AND CONTINUOUS INTEGRATION 6 . 1

Slide 22

Slide 22 text

5.1 TESTING FRAMEWORKS C++ has great testing frameworks Catch2, googletest, doctest, etc. Unit tests are the rst layer Ensure each function outputs as expected Integration tests are for work ows Ensure each series of tasks connect correctly # Catch2 CMakeLists.txt include(CTest) add_subdirectory(tests) enable_testing() # Externals ./tests/CMakeLists.txt include( /cmake/CPM.cmake) CPMAddPackage("gh:catchorg/Catch2@2.13 add_executable(particle_tests main.cpp vector_particle-test.cpp phys_processes-test.cpp ) # Link everything target_link_libraries(particle_tests ioplib Catch2) target_compile_features(particle_tests # Project Libraries include_directories( /src/include/data_types ${PROJECT_SOURCE_DIR}/src/include/) # ---- Run tests ---- add_test(NAME particleIOP-unit-tests COMMAND $) 6 . 2

Slide 23

Slide 23 text

5.2 WRITING TESTS #define CATCH_CONFIG_MAIN #define CATCH_CONFIG_RUNNER #include The macros must not be repeated Many more test scenarios d-SEAMS has examples O cial docs are great Try xing gravity as homework! Open a PR (pull request) when done #include #include #include #include #include TEST_CASE("Basic Vector class tests", iopdat Vector3 a{1, 2, 3}; REQUIRE(sizeof(a) 24); REQUIRE(sizeof(a) / sizeof(1) 6); REQUIRE(sizeof(a) / sizeof(1.0) 3); iopdat Vector3 b{4, 5, 6}; b += a; REQUIRE(b.x 5); REQUIRE(b.y 7); REQUIRE(b.z 9); std cout b.x; } sha256:d9ded32 6 . 3

Slide 24

Slide 24 text

5.3 CONTINUOUS INTEGRATION No one likes switching computers to test MacOS, Windows (WSL often), Many Linux distributions Some tests run for a long time Less attractive locally nixpkgs can take over a day! There are far too many options nowadays Wercker, Travis CI, Shippable, GitLab CI, Github Actions Mostly transient docker or nix based systems Setup can be annoying without nix 6 . 4

Slide 25

Slide 25 text

5.4 GITHUB ACTIONS local tests act allows name: CMake on: [push] env: BUILD_TYPE: Release jobs: build: runs-on: ${{ matrix.OS }} name: "${{ matrix.BUILD_TYPE }}" strategy: matrix: include: - BUILD_TYPE: Debug OS: ubuntu-latest - BUILD_TYPE: Debug OS: macos-latest - BUILD_TYPE: Debug ARCH: x86_64 OS: windows-latest # broken steps: - uses: actions/checkout@v2 - name: Create Build Environment run: cmake -E make_directory ${{git - name: Configure CMake shell: bash working-directory: ${{github.worksp run: cmake $GITHUB_WORKSPACE -DCMAK - name: Build working-directory: ${{github.worksp shell: bash run: cmake build . config $BUIL - name: Test working-directory: ${{github.worksp shell: bash run: ctest -C $BUILD_TYPE sha256:1293af3 6 . 5

Slide 26

Slide 26 text

6 EMBEDDING AND MIXED COMPILATION 7 . 1

Slide 27

Slide 27 text

6.1 WHY EMBED? 7 . 2

Slide 28

Slide 28 text

6.1.1 VISUALS?? File I/O is su cient simulate.exe > someFile.txt import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation import pandas as pd df = pd.read_csv("someFile.txt", sep=" ") # Do stuff now Can be better for HPC systems Why embed / interpolate? 7 . 3

Slide 29

Slide 29 text

6.2 BETTER EXAMPLES 7 . 4

Slide 30

Slide 30 text

6.2.1 D-SEAMS Uses lua to expose a scripting engine Computation is still C++ Reduces compilation requirements Increases exibility [goswamiDSEAMSDeferredStructural2020] 7 . 5

Slide 31

Slide 31 text

6.2.2 EON EON uses a server client architecture Is meant for distributed use [henkelmanLongTimeScale2001]

Slide 32

Slide 32 text

7 . 6

Slide 33

Slide 33 text

7 PYBIND11 8 . 1

Slide 34

Slide 34 text

7.1 EMBEDDING PYTHON Example adapted from here pip install matplotlib CPMAddPackage( NAME pybind11 GITHUB_REPOSITORY pybind/pybind11 GIT_TAG v2.6.1 ) target_link_libraries(simulation.exe ioplib pybind11 embed) py scoped_interpreter #include #include namespace py = pybind11; int main() { std vector signal(1024); for (size_t i = 0; i < signal.size(); i) signal[i] = std exp(i / -256.0) * std cos(2 * M_PI * 8 * i / 1024.0) py scoped_interpreter guard{}; using namespace py literals; Save the necessary local variab in a Python dict py dict locals = py dict{ "signal"_a = signal, }; Execute Python code, using the saved in `locals` py exec(R"( import matplotlib.pyplot as plt plt.plot(signal) plt.show() )", py globals(), locals); } sha256:5c21716 8 . 2

Slide 35

Slide 35 text

7.1.1 SAMPLE RUN

Slide 36

Slide 36 text

8 . 3

Slide 37

Slide 37 text

7.2 PROTON STEPPER Getters double physproc TimeStepper getX() { return p.position.x; } Accumulators std vector x, y, z; for (int i = 0; i < 1E3; i ) { ProtonStepper.Step(); if (i % 7 0) { x.push_back(ProtonStepper.getX()); } } py scoped_interpreter guard{}; using namespace py literals; py dict locals = py dict{ "x"_a = x, }; py exec(R"( )", py globals(), locals); sha256:59555bc from mpl_toolkits.mplot3d import Axes3 import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111, projection=' ax.scatter(x, y, z, c='r', marker='o') plt.show() 8 . 4

Slide 38

Slide 38 text

8 CONCLUSIONS 9 . 1

Slide 39

Slide 39 text

8.1 OMITTED TOPICS Documentation Possibly the most underrated skill in compuational work Package Management Managing OS’s HPC and Parallelism E cient data usage and algorithms Code Review Practices Scrum and teamwork Inter process communication Across networks and process, including serialization 9 . 2

Slide 40

Slide 40 text

8.2 FURTHER RESOURCES Community maintained, discusses features from C++11 onwards, spearheaded by Changkun Ou Maintained by Bjarne and Herb, great to get the pulse of the community Has a surprisingly good introduction and Package management at the system level in a reproducible manner Describes the present SOTA for documentation practices in the context of a large multi-language project Has a solid tutorial on tests and frameworks in general Modern C++ Tutorial C++ Core Guidelines Microsoft Visual Studio even some projects A Tutorial Introduction to Nix SymEngine and the Season of Docs CLion 9 . 3

Slide 41

Slide 41 text

9 THE END 10 . 1

Slide 42

Slide 42 text

9.1 BIBLIOGRAPHY Goswami, Goswami & Singh, D-SEAMS: Deferred Structural Elucidation Analysis for Molecular Simulations, Journal of Chemical Information and Modeling, 60(4), 2169-2177 . . Henkelman & Jónsson, Long Time Scale Kinetic Monte Carlo Simulations without Lattice Approximation and Prede ned Event Table, The Journal of Chemical Physics, 115(21), 9657-9666 . . . [goswamiDSEAMSDeferredStructural2020] doi [henkelmanLongTimeScale2001] link doi 10 . 2

Slide 43

Slide 43 text

9.2 THANKS! 10 . 3