Developer Guide
This section includes information for developers who want to contribute to the project. It includes information about the project structure, how to run the tests, and how to build the documentation. It also includes information about the project’s coding style and how to contribute to the project.
Project Structure
PQ is a C++ molecular dynamics simulation engine with Python bindings, organized into a modular architecture. The project follows standard C++ project conventions with clear separation between headers, source code, applications, tests, and documentation.
Core Directory Layout
The main directories are organized as follows:
- Source Code:
src/- Implementation files (.cpp) containing the core functionalityinclude/- Header files (.hpp) defining interfaces and declarationsapps/- Main application executable (PQ.cpp)
- Build System:
CMakeLists.txt- Main CMake configuration file
- Testing:
tests/- Unit tests for individual componentsintegration_tests/- Integration tests using pytest
- Documentation:
docs/- Sphinx documentation source files and build configurationREADME.md- Project overview and installation instructions
- External Dependencies:
external/- Third-party libraries (googletest, progressbar, toml++)
- Utilities:
scripts/- Build scripts, Singularity definition files, and utility scriptsexamples/- Example simulation input filesconfig/- License headers
Core Architecture
The PQ codebase is organized into functional modules, each contained in its own directory within both src/ and include/:
- Simulation Engine:
engine/- Main simulation engine and orchestrationintegrator/- Numerical integration algorithmsthermostat/- Temperature control algorithmsmanostat/- Pressure control algorithms
- Physical Models:
forceField/- MM bonded interactionsintraNonBonded/- MM intramolecular non-bonded interactionspotential/- MM intermolecular non-bonded interactionsQM/- Interface to QM runner programs
- System Setup:
input/- Input and setup file parsingsetup/- System initialization and configurationsimulationBox/- Simulation cell, molecule and atom handlingconnectivity/- Molecular topology and bonding information
- Data Management:
box/- Simulation box geometry and periodic boundary conditionsphysicalData/- Physical constants and unit conversionsoutput/- Output file generation and data writing
- Computational Infrastructure:
linearAlgebra/- Vector and matrix operationsutilities/- General utility functions and helperskernels/- Computational kernels and optimized routinestimings/- Performance profiling and timing utilities
- Advanced Features:
constraints/- Constraint algorithms (SHAKE, RATTLE, etc.)maxwellBoltzmann/- Maxwell-Boltzmann velocity initializationresetKinetics/- Kinetic energy manipulationvirial/- Virial stress tensor calculationsmpi/- MPI parallelization supportpython/- Python bindings and interfaceopt/- Optimization algorithms
- Design Patterns:
concepts/- C++20 concepts for template constraintsexceptions/- Custom exception classessettings/- Configuration and settings management
Build Configuration
The project uses CMake as its build system:
Root
CMakeLists.txtconfigures the overall projectEach major directory contains its own
CMakeLists.txtfor modular compilationExternal dependencies are managed through CMake’s FetchContent or find_package
Support for different build types (Debug, Release) and optional features (MPI support)
Software Tests
Unit Testing
Unit tests are located in the PQ/tests/ directory.
After building the project, the unit tests can be run by executing the command make test from within the build directory.
Integration Testing
Integration tests are located in the PQ/integration_tests/ directory.
To run these tests, ensure the following Python packages are installed:
In addition, the DFTB+ program package has to be installed.
You can then run the integration tests with the command pytest PQ/integration_tests.
Performance Benchmarks
The Google Benchmark suite contains local wall-clock benchmarks for core
algorithms. It is separate from the fixed-work performance checks in
benchmarks/perf.
Configure and build the suite from the repository root:
$ cmake -S . -B build-benchmark -DCMAKE_BUILD_TYPE=Release -DBUILD_WITH_BENCHMARKING=ON -DBUILD_WITH_TESTS=OFF -DBUILD_WITH_ASE=OFF $ cmake --build build-benchmark --target google_benchmarks
Run a short smoke test:
$ ctest --test-dir build-benchmark -L benchmark --output-on-failure
Run the full local suite and write JSON results to benchmark-results:
$ ./benchmarks/run_benchmarks.sh build-benchmark
The benchmarks are standalone executables in
build-benchmark/benchmarks/src. For example:
$ ./build-benchmark/benchmarks/src/benchmark_forceCalculation
See benchmarks/README.md for filtering, output, and sampling-time options.
GitHub Actions
The software workflow — from building the project to running unit and integration tests — is validated by continuous integration (CI) using GitHub Actions.
The corresponding workflow configuration files are located in the PQ/.github/workflows/ directory.
Coding Style
The C++ source code is formatted with clang-format using the project configuration in PQ/.clang-format.
Use clang-format version 16 or newer. Older versions do not support all options used in the current configuration, and different clang-format versions can produce different formatting.
When changing C++ files, format the touched files before committing them.
Documentation
Sphinx
This documentation is written as reStructuredText files .rst and converted to HTML website files by Sphinx .
The respective source files are located in PQ/docs/sphinx/src/.
In order to compile the files locally you need to install the following Python packages:
The project is built by running make html in the folder PQ/docs/sphinx/.
The resulting website can be viewed by opening the file PQ/docs/sphinx/_build/html/index.html via your favorite browser.
Doxygen
PQ includes comprehensive API documentation generated using Doxygen. This documentation provides detailed information about all classes, functions, methods, and their usage throughout the codebase. The documentation is automatically extracted from specially formatted comments in the source code using Doxygen markup syntax. To generate the Doxygen documentation, you need to have Doxygen installed on your system. The documentation can be built as follows:
Enable documentation during CMake configuration:
$ cmake .. -DBUILD_WITH_DOC=ONBuild the documentation:
$ make docsView the documentation:
$ <browser> build/docs/html/index.html
How to Contribute
For anyone willing to contribute to the project, it is important to understand the branching model used by the project.
The project uses the git-flow branching model.
Furthermore, git hooks for commit messages need to be enabled.
In order to contribute to the project, please follow these steps:
Fork the project on GitHub. (not necessary if you are a member of the project)
Clone your fork locally:
$ git clone https://github.com/MolarVerse/PQ.gitEnable automated commit message validation by installing the provided git hook:
$ cp .githooks/commit-msg .git/hooks/Initialize
git-flowand use the following settings (if not specified default settings are used)$ git flow init [master] main [develop] dev [version tag prefix] vCreate a feature branch for your contribution:
$ git flow feature start <feature_branch_name>Commit your changes to your feature branch and publish your feature branch:
$ git add <files> $ git commit -m "commit message" $ git flow feature publish <feature_branch_name>Add a changelog fragment describing your change (see Changelog Fragments below).
Create a pull request on GitHub.
Changelog Fragments
PQ does not accumulate changelog entries by hand-editing CHANGELOG.md
or DEV-CHANGELOG.md. Instead, every regular pull request adds a small
Markdown file, a fragment, under PQ/changes/, and a CI check
(changelog.yml) fails the pull request if none is present. At release
time, scripts/update_changelog.py routes every fragment into the right
changelog section, stamps a release header, and deletes the fragments it
consumed.
Fragments live in one of two audience directories:
changes/user/— for changes an installed-PQ user would notice: behavior, results, inputs, outputs, errors, compatibility, or runtime performance.
changes/developer/— for build tooling, CI, tests, refactors, and other internal maintenance.
Within either directory, a fragment is named:
<category>.<title>.md
<category> selects the changelog section the entry is rendered under and
must be one of the fixed categories for that audience (see
changes/README.md for the full list, e.g. bugfix, enhancement,
performance, build, ci, test, internal,
documentation). <title> is a short, free-text, lowercase-with-hyphens
slug identifying the change; it is only used to keep filenames unique and
does not appear in the rendered changelog.
A fragment’s body is one or more Markdown bullets, one per line, with no blank lines in between. Each bullet becomes its own line in the changelog:
- Fix wrong virial mode when using atomic virial after copying physical data.- First point about this change. - Second, related point about the same change.
If your pull request extends a change that already has an unreleased
fragment, append another bullet to that existing file instead of creating a
new one. A pull request may add new fragments, append to existing ones, or
both, and may touch both audiences, but it must not delete unreleased
fragments or edit CHANGELOG.md / DEV-CHANGELOG.md directly.