3. Style Guide for OpenMC

In order to keep the OpenMC code base consistent in style, this guide specifies a number of rules which should be adhered to when modified existing code or adding new code in OpenMC.

3.1. C++

3.1.1. Automatic Formatting

To ensure consistent styling with little effort, this project uses clang-format. The repository contains a .clang-format file that can be used to automatically apply a consistent format. The easiest way to use clang-format is to run tools/dev/install-commit-hooks.sh to install a post-commit hook that gets executed each time a commit is made. Note that this script requires that you already have clang-format installed. In addition, you may want to configure your editor/IDE to automatically runs clang-format using the .clang-format file whenever a file is saved. For example, Visual Studio Code includes support for running clang-format.

Note

OpenMC’s CI uses clang-format version 15. A different version of clang-format may produce different line changes and as a result fail the CI test.

3.1.2. Miscellaneous

Follow the C++ Core Guidelines except when they conflict with another guideline listed here. For convenience, many important guidelines from that list are repeated here.

Conform to the C++14 standard.

Always use C++-style comments (//) as opposed to C-style (/**/). (It is more difficult to comment out a large section of code that uses C-style comments.)

Do not use C-style casting. Always use the C++-style casts static_cast, const_cast, or reinterpret_cast. (See ES.49)

3.1.3. Source Files

Use a .cpp suffix for code files and .h for header files.

Header files should always use include guards with the following style (See SF.8):

#ifndef OPENMC_MODULE_NAME_H
#define OPENMC_MODULE_NAME_H

namespace openmc {
...
content
...
}

#endif // OPENMC_MODULE_NAME_H

Avoid hidden dependencies by always including a related header file first, followed by C/C++ library includes, other library includes, and then local includes. For example:

// foo.cpp
#include "foo.h"

#include <cstddef>
#include <iostream>
#include <vector>

#include "hdf5.h"
#include "pugixml.hpp"

#include "error.h"
#include "random_lcg.h"

3.1.4. Naming

Struct and class names should be CamelCase, e.g. HexLattice.

Functions (including member functions) should be lower-case with underscores, e.g. get_indices.

Local variables, global variables, and struct/class member variables should be lower-case with underscores (e.g., n_cells) except for physics symbols that are written differently by convention (e.g., E for energy). Data members of classes (but not structs) additionally have trailing underscores (e.g., a_class_member_).

The following conventions are used for variables with short names:

  • d stands for “distance”

  • E stands for “energy”

  • p stands for “particle”

  • r stands for “position”

  • rx stands for “reaction”

  • u stands for “direction”

  • xs stands for “cross section”

All classes and non-member functions should be declared within the openmc namespace. Global variables must be declared in a namespace nested within the openmc namespace. The following sub-namespaces are in use:

  • openmc::data: Fundamental nuclear data (cross sections, multigroup data, decay constants, etc.)

  • openmc::model: Variables related to geometry, materials, and tallies

  • openmc::settings: Global settings / options

  • openmc::simulation: Variables used only during a simulation

Accessors and mutators (get and set functions) may be named like variables. These often correspond to actual member variables, but this is not required. For example, int count() and void set_count(int count).

Variables declared constexpr or const that have static storage duration (exist for the duration of the program) should be upper-case with underscores, e.g., SQRT_PI.

3.1.5. Documentation

Classes, structs, and functions are to be annotated for the Doxygen documentation generation tool. Use the \ form of Doxygen commands, e.g., \brief instead of @brief.

3.2. Python

Style for Python code should follow PEP8.

Docstrings for functions and methods should follow numpydoc style.

Python code should work with Python 3.7+.

Use of third-party Python packages should be limited to numpy, scipy, matplotlib, pandas, and h5py. Use of other third-party packages must be implemented as optional dependencies rather than required dependencies.

Prefer pathlib when working with filesystem paths over functions in the os module or other standard-library modules. Functions that accept arguments that represent a filesystem path should work with both strings and Path objects.