ParamHelper is a C++ library that allows easy tracking of all parameters of a simulation. The parameters can be written to file and loaded for a potential rerun of the simulation. The core of the library uses JSON for Modern C++.
Building ParamHelper requires:
- A C++17-compliant compiler (e.g., g++ >= 9)
- CMake
>= 3.18
- Doxygen (optional, for documentation)
- Python with Sphinx and Breathe (optional, for advanced documentation)
The recommended way to build ParamHelper is with an out-of-source build:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
You can customize the build with these CMake variables (add as -D<var>=ON|OFF
):
BUILD_TESTING
: Enable building of the test suite (default:ON
)BUILD_DOCS
: Enable building the documentation (default:ON
)
Note: All dependencies (including Catch2 for testing and nlohmann_json for JSON support) are automatically downloaded using CMake's FetchContent.
You do not need to initialize or update any git submodules.
To install the library locally:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/local
cmake --build build --target install
If you install to a custom location, set CMAKE_PREFIX_PATH
when using ParamHelper in other projects:
cmake -S . -B build -DCMAKE_PREFIX_PATH=$HOME/local
To build and run the test suite:
cmake -S . -B build -DBUILD_TESTING=ON
cmake --build build
cd build
ctest
To build the documentation (requires Doxygen and Sphinx):
cmake -S . -B build -DBUILD_DOCS=ON
cmake --build build --target paramhelper_doxygen
cmake --build build --target paramhelper-sphinx-doc
Example use cases can be found in the examples/
directory. To build the examples:
cmake -S examples -B examples/build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$HOME/local
cmake --build examples/build
Run the example with:
./ParamHelperExamples
The example is explained in the following in more detail.
Use case: We want to manage the parameters of a class Rectangle that can be used to compute the area of a rectangle.
The class RectangleParameter contains all parameters that are supossed to be tracked:
#include "param_helper/params.hpp"
using namespace param_helper::params;
class RectangleParameters : public Parameters
{
public:
explicit RectangleParameters(const json params) : Parameters(params),
length(get_entry<double>("length", 1.0)),
width(get_entry<double>("width", 1.0))
{}
explicit RectangleParameters(const double length_=1.0, const double width_=1.0) :
RectangleParameters(json {{"length", length_}, {"width", width_}})
{}
static std::string name()
{
return "Rectangle";
}
private:
friend class Rectangle;
double length;
double width;
};
The actual class Rectangle has been defined as a friend to the class RectangleParameter. The class implements all functionalities:
class Rectangle
{
public:
explicit Rectangle(const RectangleParameters rp_) : rp(rp_)
{}
double get_area() const
{
return rp.length * rp.width;
}
private:
const RectangleParameters rp;
};
Access on the parameters is provided by the member variable rp. The class Reactangle can be used as follows:
// The project root can be adapted by params_helper::proj::set_relative_path_to_project_root_dir
std::cout << "Current directory: " << param_helper::proj::project_root() << std::endl;
// Generate parameters and write them to file
RectangleParameters rp(2.0, 3.0);
// Generates the directory parameters/ relative to the project_root
param_helper::fs::generate_directory_if_not_present("parameters", true);
rp.write_to_file("parameters", "rectangle_parameters", true);
// Optional
param_helper::fs::check_if_parameter_file_exists("parameters", "rectangular_parameters");
// Reload the parameters
auto params2 = Parameters::create_by_file("parameters", "rectangle_parameters");
RectangleParameters rp2(params2.get_json());
// Alternative way
RectangleParameters rp3(
param_helper::fs::read_parameter_file("parameters", "rectangle_parameters", true)
);
// Generate object with respective parameters
Rectangle rectangle2(rp3);
std::cout << "\nCompute rectangle area: " << rectangle2.get_area() << "\n" << std::endl;
In the example, a json file "rectangle_parameters.json" has been stored in the directory "parameters":
{
"length": 2.0,
"width": 3.0
}
With g++:
g++ param_helper_examples.cpp -I $HOME/local/include/ $HOME/local/lib/libparamhelper.a -o main
With CMake (CMakeLists.txt):
find_package(ParamHelper CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE paramhelper::paramhelper)
If installed locally, set CMAKE_PREFIX_PATH
when calling CMake:
cmake -S . -B build -DCMAKE_PREFIX_PATH=$HOME/local
The library also provides an easy way to combine several parameter files
Parameters project_params = Parameters::create_by_params(
json {{"name", "project_a"}, {"details", "rectangle_analysis"}}
);
RectangleParameters rp_analysis(2.0, 3.0);
project_params.append_parameters(rp_analysis);
param_helper::fs::generate_directory_if_not_present("project", true);
project_params.write_to_file("project", "rectangle_analysis", true);
// Add additional_project parameters to the already existing project file based on the given path
Parameters additional_project_params = Parameters::create_by_params(
json {{"type", "type_b"}, {"n", "100"}}
);
additional_project_params.merge_to_file("project", "rectangle_analysis", true);
// Reload updated parameters
auto updated_project_params = Parameters::create_by_file("project", "rectangle_analysis");
std::cout << "Updated project params " << updated_project_params << std::endl;
A folder "project" has been created that contains a "rectangle_analysis.json" file, that contains also the rectangle parameters:
{
"Rectangle": {
"length": 2.0,
"width": 3.0
},
"details": "rectangle_analysis",
"n": "100",
"name": "project_a",
"type": "type_b"
}
Examples for using the base class Parameter. The class Parameter is a wrapper to manage access and further functions on a nohlmann::json object.
#include "param_helper/params.hpp"
using namespace param_helper::params;
Parameters params = Parameters::create_by_params(
json {{"a", 0}, {"vec", std::vector<double> {0.0, 1.0}}}
);
params.add_entry("c", "c");
std::cout << "Parameters: " << params << std::endl;
auto a = params.get_entry<double>("a");
auto b = params.get_entry<double>("b", 1.0, true);
std::cout << "Extracted parameters: a " << a << " " << "b " << b << "\n" << std::endl;
std::cout << "Looking for parameter b: " << params.haskey("b") << std::endl;
// Delete entry with "b"
params.delete_entry("b");
// Get raw nohlmann json file
json params_json = params.get_json();
std::cout << "\nParams json object: " << params_json << "\n" << std::endl;
Manipulation of json objects (merge and subtract)
json additional_parameters = {{"e", 0.0}, {"f", std::complex<double> {1.0, 1.0}}};
params_json = merge(params_json, additional_parameters);
params_json = subtract(params_json, additional_parameters);
The project was generated with the help of the cookiecutter-cpp-project of the Scientific Software Center, IWR, Heidelberg University.
For bug reports/suggestions/complaints please file an issue on GitHub or start a discussion on our mailing list: statphysandml@thphys.uni-heidelberg.de.