Thursday, June 8, 2017

Announcing GooFit 2.0

The next version of the CUDA/OpenMP fitting program for HEP analysis, GooFit 2.0, has been released. GooFit is now easy to build on a wide variety of Unix systems, and supports debuggers and IDEs. GooFit is faster, has unit tests, and working examples. More PDFs and examples have been added, as well as newly released example datasets that are downloaded automatically. GooFit now has built in support for MPI, and can use that to deploy to multiple graphics cards on the same machine. A new command line parser (CLI11) and drastically improved logging and errors have made code easier to write and debug. Usage of GooFit specific terminology is now reduced, using standard Thrust or CUDA terms when possible, lowering the barrier for new developers. A new Python script has been added to assist users converting from pre 2.0 code.

Thursday, June 1, 2017

Announcing CLI11 Version 1.0

CLI11, a powerful library for writing command line interfaces in C++11, has just been released. There are no requirements beyond C++11 support (and even <regex> support not required). It works on Mac, Linux, and Windows, and has 100% test coverage on all three systems. You can simply drop in a single header file (CLI11.hpp available in releases) to use CLI11 in your own application. Other ways to integrate it into a build system are listed in the README.

Friday, March 17, 2017

Perfect forwarding for methods

I often see perfect forwarding listed for constructor arguments, but not usually for functions with a return or methods. Here is my solution for an method method of class Cls

template<typename ...Args>
static auto method(Cls* cls, Args &&  ...args)
  -> typename std::result_of<decltype(&Cls::method)(Cls, Args...)>::type {
    return cls->method(std::forward<Args>(args)...);
}

This is useful if you want to call protected classes from a “helper” friend class, for example, to expose them to tests without having to require GoogleTest/GoogleMock to be avaible for regular users.

Wednesday, January 11, 2017

Lua Environment Modules

This is a guide to setting up Lmod (lua environment modules) on a CentOS system. I’ve used a similar procedure to set them up on a Mac, as well, so this is still a useful guide to the workings of Lmod if you use a different system; mostly paths will change. On a Mac, you’ll want to install Lmod from the science tap in brew.
There are several good pages covering environment modules (TCL version), but not many that use the newer Lua syntax. This document aims to fill that roll.

Thursday, December 15, 2016

Setting up environment modules

Note: please use Lmod instead. It is a newer project that is backward compatible, but also makes some nice improvements. It is used on many supercomputer systems. See my next article.

The environment modules project is an ideal way to set up (albeit mostly manually) your environment for multiple packages. This is a quick guide on setting it up.
First, install the environment-modules (CentOS) package with yum. You’ll also need to initialize it in the bashrc file, I chose to add source /usr/share/Modules/init/bash (and optionally bash_completion) to /etc/bashrc instead of running /usr/share/Modules/bin/add.modules, but if you only want it locally, that’s also an option.
To set up a module file, you want something like this, for example /usr/share/Modules/modulefiles/cuda/8.0:
#%Module1.0
proc ModulesHelp { } {
        global version prefix name
        puts stderr "$name/$version - loads the environment for $name, in $prefix"
}

set     name      cuda
set     version   8.0

module-whatis   "loads the $name environment"

set prefix /usr/local/cuda-$version

prepend-path     LD_LIBRARY_PATH     $prefix/lib64
prepend-path     PATH                $prefix/bin
You can generate the meat of this file by doing, for example for ROOT:
/usr/share/Modules/bin/createmodule.py /opt/root-6.08.02/bin/thisroot.sh > /usr/share/Modules/modulefiles/root/6.08.02
You can remove most or all the default modules - and yes you’ll need to make modules for each package. The “spider” search does not seem to be in the standard modules package.
Note: I used http://dillinger.io to generate the this page.

Friday, March 25, 2016

GoogleTest and CMake

This is a quick recipe for setting up CMake to use googletest in your projects. First, make a tests folder in the root of your project. Then, add add_subdirectory(tests) to your CMakeLists.txt, after you've finished adding the libraries in your project. Note that the way I've written this probably requires CMake 3.4+.

The CMakeLists.txt file in tests should look like this:

set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

This adds the Threads::Threads target that we can link to, to enable the threading support that GTest requires. On some systems, it is important to use the -pthread flag, so this does that if necessary.

include(ExternalProject)

ExternalProject_Add(
    gtest
    URL http://googletest.googlecode.com/files/gtest-1.7.0.zip
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest
    URL_MD5 2d6ec8ccdf5c46b05ba54a9fd1d130d7
    INSTALL_COMMAND ""
)

ExternalProject_Get_Property(gtest source_dir binary_dir)

We have to add an external property, to get CMake to download and build GTest for us. We also need to get the source directory and binary directory for use in linking.

add_library(libgtest INTERFACE)
add_dependencies(libgtest gtest)
target_link_libraries(libgtest
    INTERFACE Threads::Threads
              "${binary_dir}/libgtest_main.a"
              "${binary_dir}/libgtest.a")
target_include_directories(libgtest INTERFACE "${source_dir}/include")

Hopefully these lines are familiar to you; they are setting up a special target that we aren't "building", but are using. The target libgtest is simply an interface (no building), and is dependent on gtest (That has to be built first). The link and include commands set up the dependencies so that future target_link_libraries commands only need this target, and will inherit everything else!

enable_testing()

This prepares CTest to handle the tests. You can either run the binaries, or use "make test" to run the tests through CTest's runner program.

file(GLOB test_cases *.cpp)

Or however you want to collect your test cases.

foreach(case_file ${test_cases})
    get_filename_component( case_name ${case_file} NAME_WE )
    set (case_name test_${case_name})
    add_executable(${case_name} ${case_file})
    target_link_libraries(${case_name} libgtest MyLibrary)
    add_test(NAME ${case_name}
             COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${case_name}
             WORKING_DIRECTORY
             ${PROJECT_BINARY_DIR}
             )

endforeach()

Here, we make the tests, doing two things. Setting up the CTest integration is the bulk of the commands above; the main command is the target_link_libraries, which should have your library target (MyLibrary in this example) and the libgtest target. That gets all the includes and links (and defs, if you have those) set on the test targets. That's it!