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
/*.cpp
files 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_ptr
std::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
,Ensures
andAssert
macros to express preconditions, postconditions and invariants. There are available insrc/utils/Exceptions.h
header. - 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.