SIRIUS 7.5.0
Electronic structure library and applications
Coding style

Below are some basic style rules that we follow:

  • Page width is approximately 120 characters. Screens are wide nowadays and 80 characters is an obsolete restriction. Going slightly over 120 characters is allowed if it is requird for the line continuity.
  • Indentation: 4 spaces (no tabs)

    Exception: class access modifiers are idented with 2 spaces

    class A
    {
    private:
    int n_;
    public:
    A();
    };
  • Comments are inserted before the code with slash-star style starting with the lower case:
    // call a very important function
    do_something();
  • Spaces between most operators:
    if (i < 5) {
    j = 5;
    }
    for (int k = 0; k < 3; k++)
    int lm = l * l + l + m;
    double d = std::abs(e);
    int k = idx[3];
    int lm(int l, int m)
    Get composite lm index by angular index l and azimuthal index m.
    Definition: specfunc.hpp:50
  • Spaces between function arguments:
    double d = some_func(a, b, c);
    but not
    double d=some_func(a,b,c);
    and not
    double d = some_func( a, b, c );
  • Spaces between template arguments, but not between <,> brackets:
    std::vector<std::array<int, 2>> vec;
    but not
    std::vector< std::array< int, 2 > > vec;
  • Curly braces for classes and functions start form the new line:
    class A
    {
    ....
    };
    inline int num_points()
    {
    return num_points_;
    }
  • Curly braces for if-statements, for-loops, switch-case statements, etc. start at the end of the line:
    for (int i: {0, 1, 2}) {
    some_func(i);
    }
    if (a == 0) {
    std::printf("a is zero");
    } else {
    std::printf("a is not zero");
    }
    switch (i) {
    case 1: {
    do_something();
    break;
    case 2: {
    do_something_else();
    break;
    }
    }
  • Even single line 'if' statements and 'for' loops must have the curly brackes:
    if (i == 4) {
    some_variable = 5;
    }
    for (int k = 0; k < 10; k++) {
    do_something(k);
    }
  • Reference and pointer symbols are part of type:
    std::vector<double>& vec = make_vector();
    double* ptr = &vec[0];
    auto& atom = unit_cell().atom(ia);
  • Const modifier follows the type declaration:
    std::vector<int> const& idx() const
    {
    return idx_;
    }
    // or
    auto const& atom = unit_cell().atom(ia);
  • Names of class members end with underscore:
    class A
    {
    private:
    int lmax_;
    };
  • Setter method starts from set_, getter method is a variable name itself:
    class A
    {
    private:
    int lmax_;
    public:
    int lmax() const
    {
    return lmax_;
    }
    void set_lmax(int lmax__)
    {
    lmax_ = lmax__;
    }
    };
    int lmax(int lmmax__)
    Get maximum orbital quantum number by the maximum lm index.
    Definition: specfunc.hpp:56
    However, the new style for setter methods is preferable:
    class A
    {
    private:
    int lmax_;
    public:
    int lmax() const
    {
    return lmax_;
    }
    int lmax(int lmax__)
    {
    lmax_ = lmax__;
    return lmax_;
    }
    };
  • Order of class members: private, protected, public
    class A
    {
    private:
    int lmax_;
    void bar();
    protected:
    void foo();
    public:
    int lmax() const
    {
    return lmax_;
    }
    };
  • Single-line functions should not be flattened:
    struct A
    {
    int lmax() const
    {
    return lmax_;
    }
    };
    but not
    struct A
    {
    int lmax() const { return lmax_; }
    };
  • Header guards have a standard name: double underscore + file name in capital letters + double underscore
    #ifndef __HEADER_HPP__
    #define __HEADER_HPP__
    ...
    #endif // __HEADER_HPP__
  • Variable names are all in lowercase and underscore-separated (aka 'snake_case'):
    int num_bands;
    std::complex<double> beta_psi;
    but not
    int NumBands;
    // or
    std::complex<double> BetaPsi;
    // or
    std::complex<double> Another_BetaPsi;

We use clang-format utility to enforce the basic formatting style. Please have a look at .clang-format config file in the source root folder for the definitions and use helper script 'clang_format.x'.

Class naming convention.

Problem: all 'standard' naming conventions are not satisfactory. For example, we have a class which does a DFT ground state. Following the common naming conventions it could be named like this: DFTGroundState, DftGroundState, dft_ground_state. Last two are bad, because DFT (and not Dft or dft) is a well recognized abbreviation. First one is band because capital G adds to DFT and we automaticaly read DFTG round state.

Solution: we can propose the following: DFTgroundState or DFT_ground_state. The first variant still doens't look very good because one of the words is captalized (State) and one (ground) - is not. So we pick the second variant: DFT_ground_state (by the way, this is close to the Bjarne Stroustrup's naiming convention, where he uses first capital letter and underscores, for example class Io_obj).

Some other examples:

  • class Ground_state (composed of two words)
  • class FFT_interface (composed of an abbreviation and a word)
  • class Interface_XC (composed of a word and abbreviation)
  • class Spline (single word)

Exceptions are allowed if it makes sense. For example, low level utility classes like 'mdarray' (multi-dimensional array) or 'pstdout' (parallel standard output) are named with small letters.