This documentation page describes coding guidelines and sums up the most important code interfaces.
RAMPACK is written in C++17. At the moment, the source code does not follow any particular coding style (which may change). General rules read as follows:
- Please try to mimic how the existing codebase is formatted.
- Use 4 spaces instead of tabs.
- The line length limit is 120 characters.
- Naming conventions:
- classes:
PascalCase - class methods:
camelCase - global functions:
snake_case - function/method arguments:
camelCase - class fields:
camelCase - variables:
camelCase - constants/enum values:
SNAKE_CASE_ALL_CAPS
- classes:
- Usually a single
*.h/*.cppfiles pair contains a single class with the same name. Sometimes helper types connected with this class (exception classes, enums) may reside in the same file. - Block opening brackets
{are usually in the same line as the loop/function/conditional etc. The exceptions are multiline function signatures - then{should always be in a separate line. - Avoid too long functions - they should follow Single Responsibility Principle and can be broken into smaller parts if needed.
- Speaking of SRP, follow good coding practices - SOLID, DRY, etc.
- Avoid manual memory management (
new,malloc, etc.) - use smart pointers. If possible, avoid heap memory altogether. Prefer, in this order:- automatic objects passed as (const) references
std::unique_ptrstd::shared_ptr
- Prefer references to pointers - references are less likely to point to some gibberish. You want an optional value?
Use
std::optional. - Use GSL-like
Expects,EnsuresandAssertmacros to express preconditions, postconditions and invariants. There are available insrc/utils/Exceptions.hheader. - Generally, write a code that you-in-the-six-months will understand. Other developers might then have a slight chance of understanding it as well ;-)
- Write unit/validation tests for your shiny new features.
- Try to make your code in a general fashion. As an example - if you add a new shape resembling a star, make the number of rays a parameter.
The project root contains the following files/directories:
.github/- GitHub specific configurations (workflows, etc.)artwork/- logosdocs/- documentation pagessample_inputs/- example input filesscript/- miscellaneous dev tools, tab completion scriptssrc/- the source codetest/- unit and validation tests and testing infrastructureCMakeLists.txt- root CMake build configuration fileDoxyfile- Doxygen configuration
The source code is divided into several directories/packages:
core/- all classes doing the heavy-liftingfrontend/- command line frontend code and definitions of PYON classesgeometry/- math and geometry classespyon/- PYON foundation frameworkutils/- various tools not fitting in other directories
The test code has the following directories:
matchers- Catch2 custom matchersmocks- trompeloeil mocks' declarationsunit_test- unit tests with the directory structure mimicking thesrc/directory (JUnit-like)validation_test- validation tests
The central point is the core/Simulation class, which performs the runs. Monte Carlo moves, sampled by implementations
of core/MoveSampler (for particle moves) and core/TriclinicBoxScaler (for box moves) are delegated to the
core/Packing class, which stores the simulation box. The Packing class uses core/NeighbourGrid for a constant-time
lookup of neighboring particles. core/DomainDecomposition class is responsible for handling domain division and ghost
layers. Parallelization is done using OpenMP code extensions. Dynamic simulation parameters (temperature and pressure)
implement src/DynamicParameter interface.
Shape and interactions are controlled by implementations of src/ShapeTraits. The interface exposes 3 sub-interfaces:
core/ShapeGeometry for geometric properties (shape axes, named points, etc.), core/Interaction for overlap
detection and/or interaction energy calculation, and core/ShapePrinter for printing out the shape in a given format.
The observables are collected by core/ObservablesCollector, trajectories are recorded using implementations of
core/SimulationRecorder interface and snapshots are stored by implementations of core/SnapshotWriter.
All observables implement core/Observable interface, while bulk observables - core/BulkObservable.
Observables have a set of helper interfaces, such as core/observables/CorrelationFunction for two-particle correlation
functions, core/observables/ShapeFunction mapping a single shape to one or more values, or
core/observables/correlation/PairEnumerator for enumerating pairs of particles.
There is a whole subsystem devoted to preparing initial arrangements. The class lattice/Lattice stores the information
about the unit cell. Is can be then modified by classes implementing the lattice/LatticeTransformer interface.
Finally, the lattice is populated using implementations of the lattice/LatticePopulator interface.
All runtime polymorphic classes are exposed to the user by their PYON bindings.
The PYON subsystem is implemented in pyon subdirectory. It is based on the so-called matchers that map PYON
structures to C++ objects. All PYON matchers reside in the frontend/matchers subdirectory.
See Contributing.md.