WARPXM v1.10.0
Loading...
Searching...
No Matches
WARPXM coding standards

The following contains coding standards for the WARPXM coding project.

Files and folders

  • Folder names will be lowercase with underscores: apps, dfem\variable_adjusters\boundary_condition\.
  • File names will be lowercase with underscores. The use of WARPXM version designators at beginning of files is deprecated. Examples: ndg.cc, oscillating_wall.h.
  • File types will be designated as follows:
    • **.cc** for C++ implementation files.
    • **.h** for C++ header files.
    • **.py** for Python files.
    • **.md** for markdown.

Input files

WARPXM input files contain information for the set up of a WARPXM simulation (see page on working with input files for more details).

Input file names often use the run name (default behavior for warpy generated input files). Otherwise filenames should be descriptive enough to distinguish them from a mesh file, which can share the same filename extension .inp.

WARPXM input files are written in XML format. When using the warpy library to run WARPXM simulations, the input file will be generated, and formatted, atomically.

<tag>
Type = TypeName
Kind = kindName
CryptsetVariableInt = 0
CryptsetVariableFloat = 0.111
CryptsetVariableVector = [0.1, 0.2, 0.3]
<\tag>

Naming conventions

The input file is case sensitive! Naming conventions have not been strictly followed in the past. Below is a list of common, and suggested, conventions:

  • Block tag names are specified by the user when setting up a simulation. They should be descriptive and unique. The convention is lower case with underscore separation: plasma_gradient_ic, dt_controller.
  • Type names indicate the parent type of the object being created by the block (variable, mesh, host action, solver base, etc.). All the major types already exist, and it is not very likely that new types will be created. In order to be interpreted correctly, the type name in the input file must correspond to the established type name exactly. Current conventions are sometimes upper camel case, sometimes lower case with underscore separation: WmSolverBase, WmHostAction, mesh.
  • Kind names indicate the object type, and are specified at the class level in the corresponding .cc file as a register string. When creating new kind names, conventions are either lower camel case, or lower case with underscore separation for apps: WmSolver, patchProcessor, explicit_runge_kutta.
  • Variables are set in the C++ class definition setup method. Convention currently varies a lot, but the preferred standard is upper camel case, and should be descriptive: BasisArraySet, OutputFileName, DensityMin.

C++ code

The primary language of WARPXM is C++. Much of what is described here are standard C++ coding conventions, plus some preferences particular to this project.

Header files

Header files (indicated in this project by .h) contain all declarations, along with a number of other important procedural functions that are useful to have separated from the meaty details in the implementation file. This list includes:

  • Include guards. Include guards prevent a header file from being included more than once during compilation. WARPXM previously used the #ifndef style include guard, but now uses the #pragma once convention as it is now widely supported and reduces the chance for programmer error. For more details on the pros and cons of both see this discussion.

    Old style

#ifndef WXM_APPS_5MOMENT_EULER_H
#define WXM_APPS_5MOMENT_EULER_H
// Wm includes
namespace wxm
{
namespace apps
{
namespace five_moment
{
class euler_t : public WMapplication
{
stuff...
more stuff...
};
} // namespace five_moment
} // namespace apps
} // namespace wxm
#endif // WXM_APPS_5MOMENT_EULER_H
Base namespace for everything not included in the global namespace.
Definition: field_source.h:8

New style

#pragma once
// Wm includes
namespace wxm
{
namespace apps
{
namespace five_moment
{
class euler_t : public WMapplication
{
stuff...
more stuff...
};
} // namespace five_moment
} // namespace apps
} // namespace wxm
  • Includes. Only the minimum necessary header file includes should be included in a header file :) See this discussion for more details. An common necessary header file include is a parent class to a class declaration in the header file (see previous example).
  • Declarations. All declarations for classes, structs, types, enums, etc. are made in the header file. Any definitions that take more than one or two lines of code should be reserved for the implementation file.
  • Documentation comments. All documentation comments read by the document generator will live in the header file. See documentation commenting page for more details.

Implementation, or source, files

Implementation files (indicated in this project by .cc) contain all the definitions that were not detailed in the header file.

Naming

  • Constants. All caps, separated by underscore. Not used too often: WMAPPLICATIONFLAG_INTERNALFLUX
  • Classes. Upper camel case, with only the first letter of acronyms capitalized. In the future, no WARP version indicator is necessary (Wm, Wx): Application, LogStream
  • Class instances. Lowercase, with underscores: debug_stream, patch, app
  • Private or protected class variables. Lowercase, with preceding underscore. Should be descriptive: _cfl, _omega_p_tau.
  • Public class variables. Lowercase, no preceding underscore. Should also be descriptive.
  • Local variables. Lowercase, can be brief: t, x.
  • Methods or functions. Lower camel case, descriptive: getNumLayers().

    Accessing methods or functions:

    • ClassPointer->methodName() : Accessing a public field or method by referencing a class or object pointer.
    • ClassInstance.methodName() : Accessing variables and methods via object (class instance).
    • ClassName::methodName() : Accessing static variables and methods of a class, struct, or namespace, or from another scope.
    • this->methodName() : this is a pointer to the instance of the object calling the method. It is automatically initialized. Used for when calling another objects method from within that same object. Somebody correct me.
  • Namespaces. All lower case and brief: wxm, dfem, solver
  • Type defs. Lowercase, followed by a _t. Descriptive to not interfere with standard types. Use only when necessary. _t should not be used for classes!: _t: distributed_variable_t
  • Templates. Likely won't be creating a lot of new templates. Currently referred to with single capital letters.

Formatting

Formatting conventions are outlined below. Formatting can be automatically enforced through Clang Format (instructions at end of this page).

  • Indentation. Four spaces, no tabs! Namespaces are not indented.
  • Line length. 90 characters.
  • Braces. A brace gets its own line, no blank lines before or after:
for (size_t i = 0; i < _apps.size(); ++i)
{
if (foo[i] >= 0)
{
// Do something
}
if (foo[i] < 0)
{
// Do something else
}
}
  • Spaces:
    • Spaces before and after operators +,-, and =: a = b + c
    • Spaces outside, but not inside parentheses: a = b + (c - d)
    • Above holds for for and if statements: for (int i = 0; i < 0; i++)
    • Space after, but not before commas: int[4] a = [0, 1, 2, 3]
  • Code blocks and empty lines. Code blocks should contain logically related code, preceded by a comment, and followed by an empty line:
// This block does X
x = y + z;
x = x - z;
std::cout << "x is now y, x = " << x << std::endl;
// This block does A
a = b + c;
a = a * b;
a = 0;
  • Empty lines. Should be used sparingly to create visual breaks in code where indentation, braces, or other visual indicators are not already present.

Commenting & Documentation

Comments serve two purposes:

  • Documentation comments. Documentation comments are comments formatted and positioned in a way to be interpreted by a documentation generator (WARPXM currently uses Doxygen). As they will form part of stand-alone documentation, all comments in documentation blocks must be understandable and meaningful without direct access to the code.
  • Clarification comments. Clarification comments are not captured by the documentation generator, but are intended to be read with code. As the name indicates, clarification comments serve to clarify coding choices and explain sections of code whose purpose may not be immediately obvious.

Commenting guidelines for the WARPXM project are described in the documentation commenting page.

Python code

Python is used within WARPXM for setting up and running simulations, as well as post-processing, most of which is handled by the warpy library, and Python input files located in the examples and user_runs directories.

Naming

See naming conventions for C++, with the following additions/exceptions:

  • Classes. Classes are currently all lowercase.
  • Functions. Are also currently all lowercase.

Formatting

Currently following the formatting recommendations in the PEP 8 Style Guide for Python Code. This can be automatically enforced through the yapf program (see Formatting Tools section for further details).

Commenting

See documentation commenting page.

Formatting tools

C++ formatting: clang-format

Clang Format is a formatting tool that reformats C/C++ files based on a set of rules. The .clang-format file in the top level directory of the WARPXM repository describes the formatting rules for this project.

Clang Format can be integrated into Emacs, vim, and other IDEs, or run from the command line. Please see the "Clang Format Setup Guide" in the WARPXM group Dropbox folder for setup details. Official documentation for Clang Format can be found here.

Python formatting: yapf

yapf is a Python formatting tool based on Clang Format. Usage is similar and is described here. It can be installed through source code from the previous link, or through the Python package manager Pip.

The style file for the WARPXM repository is .style.yapf, located in the top level directory.

yapf can be integrated into Emacs or Vim.

Notes on yapf

yapf is not deterministic. It uses a penalty method to decide whether to split lines or add spaces. Which means if you rerun yapf on the same file, you may not get the same result. That being said, the formatting is still more consistent than humans, and it takes the thinking out of enforcing a lot of nit-picky rules that greatly increase readability.

Following is an explanation of some of non trivial yapf formatting rules:

  • Function definition arguments. If they are too long to fit on one line, they will be listed column wise, indented to the location of the first argument.
class interspecies_collisions(application):
def __init__(self,
name,
nu_p_tau,
charge,
mass,
fluid,
fluid_components=None,
coulomb_log=1.0):
  • List comprehensions. Long list comprehensions are split before "for"s and "if"s.
result = [
a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000)
if a_var % b_var]

reformats to

result = [
a_var + b_var
for a_var in xrange(1000)
for b_var in xrange(1000)
if a_var % b_var]
  • Lists of tuples. The default behavior is to list them on one line, and occasionally do weird splitting within tuples. If the last tuple has a trailing comma, each tuple will be put on its own line.
req_attrs=[
('Kind', 'intraspecies_collisions_parabolic_13moment'),
('nu_p_norm', nu_p_tau),
('CoulombLog', coulomb_log),
('Mass', mass),
('Charge', charge),
],
  • A trailing comma at the end of any comma-separated list will put all items on their own line.