Writing Documentation

Documentation Philosophy

QDYN’s documentation is organized around four distinct categories.

the four types of documentation
  1. Examples (learning-oriented tutorials): A lesson illustrating a particular use case of QDYN. Typically a Jupyter notebook walking through a simplified version of a published paper, targeted towards a new user of QDYN. See the section on writing Jupyter Notebook Examples below.

  2. How-tos (goal-oriented guides): A guide on how to accomplish something specific with QDYN, for more experienced users. Typically written as a response to a user’s question. See the section on writing How-Tos below.

  3. Topical overviews (understanding-oriented explanations): An in-depth review of the concepts behind QDYN and how they are implemented. Targeted towards a student learning numerical methods of quantum control. See the section on writing Topical Overviews below.

  4. Reference material (information-oriented descriptions): These are typically auto-generated, e.g. QDYN’s API and config file documentation. Targeted towards QDYN developers. See the sections on Fortran Docstrings and the Config File Documentation below.

Note

Make sure to watch the What Nobody Tells You about Documentation talk that describes the motivation behind these four categories.

See also How the documentation is organized (from a user’s perspective) on the main index page.

Automatic Doc-Generation

Running make doc will use Sphinx to translate input files located in doc/sources/ to html output in doc/_build/html. During installation (make install), the contents of doc/_build/html will be copied to the install location.

Some of the files in doc/sources/ are automatically generated during make doc:

  • For every module, documentation is generated by parsing the source code of that module for lines starting with !! (“Fortran Docstrings”). The RST files for this “API” documentation are (temporarily) generated in doc/soures/api/.

  • Documentation for the different sections of the config file is (temporarily) created in doc/sources/config/sections/, via the scripts/generate_config_doc.py script. Moreover, “reference card” PDF files for the QDYN config are generated in doc/sources/config/refcard/ (via the scripts/generate_refcard.py script).

The entire process is controlled by the scripts/compile_doc.py script.

The RestructuredText Syntax (RST) markup language is used both in the static documents in doc/sources/ and when interpreting the docstrings inside modules.

Bibliographic References

The QDYN documentation uses sphinxcontrib-bibtex to manage citations, emulating citations in LaTeX. All bibliographic data is collected in a bibtex database at doc/sources/refs.bib.

The entries in this file are rendered in the central References page of the documentation in a format akin to that used in APS journals like Phys. Rev. Lett. The details of this format are defined by the ApsStyle class in doc/sources/conf.py.

Citations

In any part of the documentation, a reference is then cited as e.g.

:cite:`ReichJCP2012`

which renders as e.g. [23] and links to the corresponding entry on the References page.

In Jupyter notebooks an alternative syntax using <cite> tags with a data-cite attribute is required (see below).

The refs.bib Database

All references that are cited anywhere in the QDYN source code or documentation (and only those!) must be included in the bibtex database at doc/sources/refs.bib.

Warning

Strictly adhere to the citation key format and conventions outlined below!

  • Use an Author-Journal-Year format for the citation key. That is, the last name of the first author, followed by the initials of the journal in all caps, followed by the 4-digit year, e.g. KochPRL2003 ReichJCP2012, GoerzNPJQI2017. Resolve conflicts by appending a, b, …

  • Be consistent with the journal initials. Check the refs.bib file for existing citations with the same journal.

  • Conference contributions or book chapters use the same citation key format as journals, with the initials of the conference name or the book/series title instead of the journal name initials, e.g. KochICOLS2007 for Ref. [43].

  • For PhD theses, use e.g. GoerzThesis2015; for other theses, e.g. BlechMaster2018, BasilewitschBachelor2013, ReichDiploma2010.

  • For books, use an Author-Year format. You may concatenate the names of multiple authors, especially for books that are widely referred to by their author pair, like NielsenChuang2000

  • Avoid citing preprints. If you must, you can use e.g. arxiv1902.11284 as the citation key. Use the @article class and the full arXiv identifier (arXiv:1902.11284) for the journal-field. Replace these citations with the published version of the paper as soon as possible.

  • All journal entries must use a macro name in the journal field, e.g. prl for “Phys. Rev. Lett.”. These macros are defined at the top of the refs.bib file. The macro name should generally be the lowercase version of the journal initials used in the citation key. For journals not yet listed in refs.bib, define a new appropriate macro in refs.bib as well as in the scripts/get_bibtex.py script (see below).

  • The journal name macros must expand to the standard abbreviated journal name for that journal

  • All article entries must contain a DOI. (Nearly all articles have a DOI. Find it!)

  • Make sure that proper nouns in titles are enclosed in braces to preserve their capitalization.

  • Use unicode for accented characters in titles and author names, e.g. Mølmer, not M{\o}lmer.

  • Theses and other materials that don’t have a DOI must include a Url field.

  • For journal articles, only include the starting page, not a page range.

  • Do not include non-relevant fields (OPT keys, abstracts, unnecessary URLs) in the entry.

Note

Use the ./scripts/get_bibtex.py script to generate a proper bibtex entry for a given DOI (or URL containing a DOI), using data from https://search.crossref.org.

get_bibtex.py (depends on the click and habanero packages)

For example:

$ ./venv/bin/python ./scripts/get_bibtex.py 10.1063/1.3691827
@article{ReichJCP2012,
    Author = {Reich, Daniel M. and Ndong, Mamadou and Koch, Christiane P.},
    Title = {Monotonically convergent optimization in quantum control using {Krotov}'s method},
    Journal = jcp,
    Year = {2012},
    Doi = {10.1063/1.3691827},
    Pages = {104103},
    Volume = {136},
    Number = {10},
}

This will automatically choose the correct key format, journal macro, protect proper nouns in the title and include all required (and only the required) fields.

See get_bibtex.py --help for more details.

If the script does not recognize a journal (i.e., there is no macro name in the journal field), edit the script and refs.bib to define an appropriate macro.

Local reference lists

Sometimes it is useful to include a list of references separate from the main References page. This is particularly relevant for documents that must stand on their own outside of the rendered HTML documentation:

  • Fortran or Python modules should list all relevant references for the implemented numerical methods in their module description.

  • Examples (Jupyter notebooks) should list the publications that they are derived from, and other key references.

Topical overviews may also include reference lists of key literature.

In all cases, each reference in such local reference lists should be prefixed with a :cite: command to link the main bibliography, followed by a shortened APS-style reference (Last names of at most two authors, or first author “et al.”, abbreviated journal, volume, page, year). E.g.,

* :cite:`PalaoPRA2003` Palao and Kosloff, Phys. Rev. A 68, 062308 (2003)
* :cite:`ReichJCP2012` Reich *et al*., J. Chem. Phys. 136, 104103 (2012)

which renders as:

  • [24] Palao and Kosloff, Phys. Rev. A 68, 062308 (2003)

  • [23] Reich et al., J. Chem. Phys. 136, 104103 (2012)

In Jupyter notebooks an alternative syntax using <cite> tags with a data-cite attribute is required (see below).

Jupyter Notebook Examples

The Examples in the QDYN documentation are tutorials designed to teach users the use of QDYN. These should be written as Jupyter notebooks if possible.

Notebooks should stand on their own: a student trying to follow them would read and run them in the Jupyter web interface. However, they are also automatically converted to RST and included in the documentation via the nbsphinx plugin. Often, an example will be simplified simulation or optimization from a published paper. However, when converting a paper to an example, remember that a scientific paper and a QDYN tutorial differ in their goals and audiences.

  • The tutorial must work, be repeatable, and show results immediately. Focus only on the steps the user needs to take. Notebooks should run through in at most few minutes on a typical workstation.

  • The goal is to enable “learning by doing” for a new user of QDYN. Write to the level of a Bachelor student.

  • Focus on concrete steps, not abstract concepts. Provide the minimum necessary explanation. The example does not need to go into details about either the underlying physics or the numerical methods. Those should be reserved for Topical Overviews.

Markdown formatting

Jupyter notebooks are a mix of code cells (usually in Python, but possibly other languages, including shell scripts) and their output, and markdown cells. Markdown is a simple markup languages widely used on the web. However, it does not have all the features of the RestructuredText Syntax used for the other parts of the documentation, especially in regard to cross-referencing. The recommended approach is to keep notebooks mostly self-contained, although the nbsphinx plugin that translates the notebooks into RST files for inclusion in the documentation provides some workarounds for linking to other parts of the documentation.

Images

Ideally, images in the notebook should be part of the output of a code cell (e.g., using matplotlib). If this is not possible, it is best to use cell attachments. This ensured that the notebook is self-contained (that is, it can be viewed by itself on https://nbviewer.jupyter.org)

Math

Inline math in a Jupyter notebook must be written in LaTeX syntax and be enclosed in dollar signs. The nbsphinx plugin will translate this into RST math directives.

In the translated notebook, the custom latex macros like \ket and \Op that are supported throughout any RST document are automatically available. However, they will not render when viewing the notebook as standalone document. To enable these macros, define them via \newcommand in inline math inside of a markdown cell. For example:

$\newcommand{ket}[1]{\vert#1\rangle}
\newcommand{Op}[1]{\hat{#1}}$

Define only the macros that are actually used in the notebook. The definitions must match the custom latex macros in the mathjax_config setting in doc/sources/conf.py. Always use semantic macros, e.g. \ket{\Psi} instead of \vert \Psi \rangle!

You can put the macro definitions directly underneath the notebook title: they will not be visible in the rendered notebook. The definitions are available in the rest of the notebook, once defined.

For equations, use standard LaTeX/amsmath equation environments like equation or align. Do not use $$...$$ or \\[...\\]: these work in the Notebook environment, but do not translate to RST in the rendered QDYN documentation.

Warning

Always check how the notebook renders both standalone in Jupyter and as part of the QDYN documentation!

The system that nbsphinx proposes for automatic equation numbering is not compatible with the :label: and :eqref: system in RST. Avoid equation numbers in Jupyter notebooks. If you need to, you may use \tag to set an explicit equation label, for example \tag{I} or \tag{☆}. You may then reference the equation inside the same notebook by writing out Eq. (I) or Eq. (☆). The reference will not be a clickable link. If you need a clickable link, you could use e.g. Eq. ([I](#mjx-eqn-I)) or Eq. ([☆](#mjx-eqn-☆). The #mjx-eqn-I and #mjx-eqn-☆ anchor names could also be used to reference the tagged equation from another document. Since the anchor names are very hacky (undocumented; Sphinx will not be able to help you with broken links), avoid such references.

Citations

Jupyter notebook markdown cells support a special syntax for bibliographic references in a way that is fully compatible with the system for Bibliographic References in the QDYN documentation.

In a Jupyter notebook markdown cell, write e.g.

Ref. <cite data-cite="RissJPB1993">[RissJPB1993]</cite>

The data-cite value must be a bibtex key in QDYN’s main refs.bib file. The contents of the <cite> tag is arbitrary; it will be shown in the standalone notebook but is stripped entirely from the rendering of the notebook as part of the QDYN documentation. When nbsphinx converts the notebook to RST for inclusion in the documentation, it replaces the entire <cite> tag with e.g. :cite:`RissJPB1993, generating a link to the main bibliography. The content of the <cite> tag may be empty, in which case it will be invisible in the standalone notebook, but produce a citation in the rendered RST.

It is recommended to collect the references cited in a notebook in a “References” section at the end, e.g.,

## References

* <cite data-cite="RissJPB1993"></cite> Riss and Meyer, J. Phys. B 26, 4503 (1993)
* <cite data-cite="ManolopoulosJCP2002"></cite> Manolopoulos, J. Chem. Phys. 117, 9552 (2002)
* <cite data-cite="BainJPB1974"></cite> Bain *et al*., J. Phys. B 7, 2189 (1974)
* <cite data-cite="BlechMaster2018"></cite> A. Blech, Master’s thesis, Universität Kassel (2018)

This is the same format used for Local reference lists elsewhere in the documentation.

How-Tos

How-tos are guides for intermediate to advanced users. They assume the user knows what they want to do, but not how. Unlike Tutorials/Examples, they are oriented towards a particular goal or problem, not towards learning. They provide a series of steps to reach that goal.

A how-to guide may be written alongside a new feature in QDYN: anything that affects the config file should usually have some how-to documentation. Beyond that, a how-to should usually be a response to an actual question. If you have a problem with QDYN that took you some effort to figure out, or someone raised a question on QDYN’s issue tracker, that is an ideal candidate for a how-to guide.

If there are multiple ways to do something, a how-to guide should discuss all of those ways and their relative trade-offs. How-tos may be Jupyter notebooks, but generally, prose in a standalone RST file is preferred. This is because how-tos are generally less “complete” than tutorials: including an entire problem setup and analysis in a how-to may detract from its core message. Be concise. How-tos generally do not contain bibliographic references.

The title for a how-to should start with “How To”.

Topical Overviews

Topical overviews are in-depth explanations of overarching concepts. These will often be the most difficult and time-consuming part of the documentation to write. They should be written to the level of a scientific publication, and use citations extensively.

The topics of these overviews can vary widely. For example:

  • An in-depth discussion of a particular numerical method

  • A review and comparison of different propagation/optimization methods

  • An record of design decisions for QDYN, or an explanation of data structures: Why things are implemented the way they are

  • An analysis of a particular physical system and how QDYN is designed to model it

They are the primary way in which detailed knowledge is communicated to future QDYN developers, as well as a source of background information for users. They should not, however, be required reading for just a basic user of QDYN. They should not take the role of how-to documents.

The topical overviews may be adapted from “methods” thesis chapters (or serve as a draft for such a chapter), from a published review paper, lecture notes, the discussions on a QDYN issue or merge request, or the supplementary material of a paper.

Unlike a published paper or thesis, topical overviews can be continuously revised and adapted, and thus represent a living body of knowledge that keeps up with the continuing development of QDYN. They also fulfill a different role than a scientific publication, in that they do not present novel scientific results, but instead maintain knowledge relevant to the use and development of QDYN.

Topical Overviews may list key references in the format described for Local reference lists. However, especially for reviews that contain a large number of citations, it should be sufficient to use the :cite: role to link to QDYN’s main References page.

Fortran Docstrings

Each module must contain docstrings that document the module and each routine, type, or interface in it, which is rendered in the API. These docstrings start with two exclamation points. Specifically, you should use the format discussed below for the various kinds of objects.

Note

The format of using double-exclamation points and tags like @description and @param (see below) are specific to Fortran code. In fact, they are specific to QDYN, inspired in QDYN’s earliest days from JavaDoc.

Python code (QDYN-pylib) must also have docstrings, but uses the popular “Google Style” format, instead of JavaDoc-inspired tags, see also the notes on the QDYN-pylib documentation. Whether Fortran docstring or Python docstrings, all text is parsed in the RestructuredText (RST) markup language.

Module Documentation

Immediately after the beginning of the module, there must be a description of the module, like this example from the qdyn module:

!! @description:
!! The :mod:`qdyn` module is the central module of the QDYN library. It
!! collects and exports routines and definitions from all other QDYN
!! modules. Therefore, in any program using the QDYN library it is
!! usually sufficient to import the :mod:`qdyn` module with
!!
!! ::
!!
!!     use qdyn
!!
!! For advanced purposes, you can still directly import any other
!! module that is part of the QDYN library.

The module description is a good place to explain the structure of the routines contained in the module and how these relate to other routines in QDYN.

If the module implements numerical methods from a particular paper, it should explicitly list those references, using a format as in the following example from the qdyn_krotov_mod module:

!! @description: Implementation of the Krotov optimization algorithm, both
!! first and second order. Which order is used is decided by the value of
!! :config:`oct:method`, which should be either `krotovpk` (first order), or
!! `krotov2` (2nd order).
!!
!! The Krotov algorithm as implemented here follows the description in
!!
!! * :cite:`ReichJCP2012` Reich et al., J. Chem. Phys. 136, 104103 (2012)
!!
!! The first order algorithm is also described, e.g., in
!!
!! * :cite:`PalaoPRA2003` Palao and Kosloff, Phys. Rev. A 68 062308 (2003)
!! * :cite:`KochPRA2004` Koch et al., Phys Rev. A 70 013402 (2004)
!!

Each reference must start with a :cite: command to link it to the corresponding entry in the main bibliography in the HTML documentation, followed by an abbreviated citation. While this duplicates information already available in the main bibliography, it served to keep the module self-contained for developers working with the source code directly.

Descriptions must not contain any headings. If necessary, a rubric may be used, e.g. for a “References” section, as in this example from the qdyn_mcwf_mod module:

!! @description:
!! Implementation of the Monte-Carlo Wave Function (MCWF) method.
!!
!! See :ref:`overview-quantum-jump-method` for a detailed overview.
!!
!! .. rubric:: References
!!
!! * :cite:`DumPRA1992` Dum et al., Phys. Rev. A 45, 4879 (1992)
!! * :cite:`MolmerJOSA1993` Mølmer et al., J. Opt. Soc. Am. B 10, 524 (1993)
!! * :cite:`MolmerQSO1996` Mølmer and Castin, Quantum Semiclass. Opt. 8, 49 (1996)
!! * :cite:`PlenioRMP1998` Plenio and Knight, Rev. Mod. Phys. 70, 101 (1998)

The module description should limit itself to the essential description of the module, be concise (a few paragraphs at most), and not contain tutorials, explanations or how-to guides. It may link to such other parts of the documentation, as in the above example.

Subroutine Documentation

All routines (subroutines/functions) must have a documentation block directly before the routine declaration, like in the following example:

!! @description: Read two columns from an ascii file.
!! @param: col1      Array for the first column
!! @param: col2      Array for the second column
!! @param: filename  File name
subroutine read_ascii_2col (col1, col2, filename)

  real (idp),        intent(inout) :: col1(:), col2(:)
  character (len=*), intent(in)    :: filename
  ...

Although only public routines are shown in the compiled documentation, both private and public routines should be documented. As a matter of style, the @param: docstrings should consist of the component name, followed by at least two spaces, and then the description, with all the descriptions lined up as in the example. The descriptions should start with a capital letter.

Interface Documentation

If a module uses overloaded routines, there must be a documentation block right before the interface, giving a description. In order to document the implementations of the interface and their parameters, there are two options:

  1. If (and only if!) all implementations have the same number of parameters and the same parameter names, these parameters should be documented with a @param docstrings below the interface description. As the parameter-docstrings do not contain information about intent, shape, and other parameters (all the information normally supplied in a variable declaration), a pseudo-declaration can be given in the documentation on a @paramdef line. For example, from the documentation of delete():

    !! @description: Delete a QDYN-type variable.
    !!
    !! The routines combined in this interface delete a variable of the
    !! corresponding type. It is used as follows:
    !!
    !! .. code-block:: fortran
    !!
    !!     call delete(var, thorough)
    !!
    !! @param: var       The variable to delete. The type of `var` can be any of
    !!                   the ones defined in :mod:`qdyn_def_mod`.
    !! @param: thorough  If given as `.true.` recursively zero out all components
    !!                   of `var`. All numbers will be set to zero, logicals to
    !!                   `.false.`, and strings to the empty string.
    !! @paramdef: intent(inout) :: var
    !! @paramdef: logical, optional, intent(in) :: thorough
    

    For variables that vary only in type between the different implementations (var in the example), no type information should be given in @paramdef; make sure that information about the accepted types is contained elsewhere in the docstring.

    Warning

    The @paramdef field must only be used inside the documentation for an interface, never for a function or subroutine!

  2. If the implementations of the interface differ in the number of parameters, the interface must only have a @description, but no @param or @paramdef declarations. Instead, every implementation must also have a documentation block, explaining the parameters. The description given for the implementations is not used, but it is still good style to supply it. For example, from the documentation of read_ascii():

    !! @description: Read data from a csv file.
    !!
    !! The columns in the file are separated by spaces. The data is read into
    !! arrays of reals, reals, one array per column. There can be up to three
    !! columns. If there are less columns in the file than you try to read,
    !! the remaining columns are filled with zeros.
    interface read_ascii
      module procedure read_ascii_1col, read_ascii_2col, read_ascii_3col
    end interface
    
    !! @description: Read a single columns from an ascii file.
    !! @param: col       Unallocated array for the column
    !! @param: filename  File name
    subroutine read_ascii_1col (col, filename)
    
      real (idp), allocatable, intent(inout) :: col(:)
      character (len=*),       intent(in)    :: filename
      !...
    

Warning

If the documentation block of an interface defines any @param or @paramdef fields, the documentation blocks of the actual implementations will not be used. Conversely, if the interface documentation block has no @param or @paramdef fields, each actual implementation will be fully rendered as part of the resulting HTML documentation.

Types Documentation

Type definitions also need a documentation block, similar to routines:

!! @description: Information about spatial grid in the config file.
!! @param: dim      Number of spacial dimensions
!! @param: r_min    Minimum :math:`r`, per dimension
!! @param: r_max    Maximum :math:`r`, per dimension
!! @param: map      Mapping, through dimensions
!! @param: maptype  Type of mapping (``'diff'``, ``'int'``)
!! @param: nr       Numer of points, per dimension
type grid_pt
  integer                :: dim
  real(idp), allocatable :: r_min(:)
  real(idp), allocatable :: r_max(:)
  logical, allocatable   :: map(:)
  character(len=5)       :: maptype
  integer, allocatable   :: nr(:)
end type

Docstring Formatting

Description docstrings may contain multiple paragraphs of text, code blocks, or display formulas. However, the docstring must start with a single-line summary, ending with a period. The summary may be on the same line as the !! @description: if it is sufficiently short, as in the example above. Otherwise, there must be a line break after the initial !! @description:, and the summary must be entirely in the second line. The reason for the summary having to be short is that the summaries are rendered in a tabular overview of the module they’re defined in, so they must be concise.

The summary must be separated from any subsequent paragraphs by a blank line, e.g.:

!! @description:
!! Complex Discrete Fourier Transform.
!!
!! Returns
!!
!! .. math::
!!
!!     X(k) = \sum_{j=0}^{n-1} x(j)
!!            \exp(\pm 2 \pi\,i\,j\,k\, / n);
!!            \quad 0 \leq k \le n
!!
!!
!! where the sign of the exponent is controlled by the
!! `isign` parameter.
!!
!! Note that the inverse of
!!
!! .. code-block:: fortran
!!
!!     call cdft(2*n, -1, a, ip, w)
!!
!! is
!!
!! .. code-block:: fortran
!!
!!     call cdft(2*n, 1, a, ip, w)
!!     do j = 0, 2 * n - 1
!!         a(j) = a(j) / n
!!     end do
!!

For parameter docstrings that contain multiple paragraphs, the documentation must be aligned in a column:

!! @param: n     ``2*n``: data length, with ``n >= 1`` and ``n`` being a
!!               power of 2
!! @param: isgn  Sign of exponent
!! @param: a     ``a(0:2*n-1)``: input/output data
!!
!!               input data::
!!
!!                   a(2*j) = Re(x(j)),
!!                   a(2*j+1) = Im(x(j)), 0<=j<n
!!
!!               output data::
!!
!!                   a(2*k) = Re(X(k)),
!!                   a(2*k+1) = Im(X(k)), 0<=k<n
!!

All docstrings use the RST syntax described below. Most importantly for docstrings:

  • Put inline code snippets in double backticks. Keywords and constants should be enclosed in single backticks, e.g. write .true. as `.true.` and 'diff' as `'diff'`.

  • Reference function argument names in single backticks:

    ...
    !! @param: from_time_i     If given, assume that the state is located at time index
    !!                         `from_time_i` in the global time grid
    !! @param: to_time_i       If given, time index at which to stop the
    !!                         propagation.  When doing backward-propagation,
    !!                         `to_time_i` should be smaller than `from_time_i`
    ...
    

    Warning

    QDYN’s Sphinx installation is configured so that single backticks and double backticks both render as code-formatted text. However, they are not semantically equivalent: double-backticks indicate “code”, whereas single backticks are the “default role”, which by convention in Sphinx are used for function arguments. For historical reasons, single and double-backticks are not always used consistently in the QDYN documentation, and the distinction between the two is not strictly enforced. However, all new documentation should try to adhere to the semantic distinction between single and double backticks.

  • Reference other functions/subroutines/interfaces as e.g. :func:`prop`. For types, use e.g. :type:`grid_t`, and for modules e.g. :mod:`qdyn_prop_mod`. This links to their documentation (prop(), grid_t, qdyn_prop_mod). Note that only public routines can be referenced.

  • Reference config file sections as e.g. :config:`prop` and items within a config file section as e.g. :config:`prop:method` or :config:`~prop:method` to suppress “prop” in the output: these examples render as prop, prop:method, and method, respectively, linking to the corresponding documentation.

  • Surround inline math with dollar signs (as in LaTeX), e.g.

    !! @param: L_psi       Array of states :math:`\Op{L}_n \Ket{\Psi}` for all of the
    !!                     Lindblad operators :math:`\Op{L}_n`.
    

    There must be no whitespace after the opening dollar sign, and no whitespace before the closing dollar sign.

Warning

The “dollar-math” syntax is a docstring-specific extension (implemented in scripts/docgen.py) and not part of the RST standard: $\Op{L}_n$ is equivalent to the standard math-role (:math:`Op{L}_n$`). Within docstrings, dollar-math it is preferred over :math:, for conciseness. The dollar-math syntax cannot be used in standalone rst files.

The dollar-math syntax only covers the inline math role. For “display math” (equations), you must use the RST math-directive, both in docstrings and in standalone rst files. You cannot use $$...$$ or \[...\] for display math.

Config File Documentation

The docstrings for types whose names in _pt are used in two contexts: as a documentation of a type, e.g. grid_pt, and for the documentation of the corresponding grid section in the config file.

The _pt types should also define a section @examples, e.g.:

!! @examples:
!! For OCT on moving grids, you will need to set up one grid for the initial
!! state, and one for the target state::
!!
!!     grid: system = initial
!!     * dim = 1, r_min = -10, r_max = 10, nr = 128, moveable = true
!!
!!     grid: system = target
!!     * dim = 1, r_min = 0.078740157480315, r_max = 20.078740157480315, &
!!       nr = 128, moveable = true
!!
type grid_pt
  character(len=label_l)      :: label
  integer                     :: dim
  real(idp)                   :: r_min
  ...

The content of this section will be included in the HTML describing the grid config file section, but not in the rendered documentation of grid_pt. Keep these examples short. Their purpose is to show which config file options typically go together. They should not take the role of how-tos!

Warning

Generally, docstrings from _pt types should be written such that they are equally suitable in both documentation contexts (the type documentation and the config file section documentation). When this is not possible, the config file documentation takes precedence. That is, when editing the documentation for a _pt type, check that the resulting HTML for the config file documentation reads well.

RestructuredText Syntax

RestructuredText (RST) is a markup language that is specifically designed for writing software documentation. Historically it originates from the Python community and is a core component of the Sphinx documentation generator.

The RST syntax is described in the Sphinx documentation at https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html (and, in full detail, in the docutils documentation linked therein)

Most of RST’s syntax is relatively straightforward, and well-described in the Sphinx documentation. The remainder of this section fills in some of the more subtle points and QDYN-specific considerations.

See also the RST files in doc/sources for extensive examples that you should imitate.

Cross-References (Roles)

RST’s greatest strength over other markup languages is its ability for cross-referencing symbols (function names, type components, etc.), via roles. This cross-referencing can be made to work even across different projects, via Intersphinx.

References to Fortran objects

The QDYN documentation extends Sphinx with a “Fortran” domain (doc/sources/_extensions/fortran_domain.py), which is also the default domain for all references (except in QDYN-pylib docstrings). You should use the following as much as possible throughout the documentation and within docstrings to reference parts of QDYN:

  • The :type: role for any types defined in QDYN’s def module, e.g. :type:`grid_t` which renders as “grid_t” to link to the grid type

  • The :typef: role for any fields within types, e.g. :typef:`grid_t%coord_type` which renders as “grid_t%coord_type” to refer to the coord_type field of grid_t.

  • The :func: role for any functions or subroutines defined in QDYN. For example, :func:`prop` refers to the prop() function in qdyn_prop_mod. You may use :subr: instead of :func: to distinguish subroutines from functions, but the two roles are equivalent and the distinction is not enforced within the QDYN documentation. Note that only public routines can be referenced in this way.

  • The :mod: role for any modules that are part of QDYN, e.g. :mod:`qdyn_grid_mod`, which renders as “qdyn_grid_mod” to refer to the grid module.

For all of the above, the text of the reference may be modified through the general :role:`text <target>` syntax (Same as Cross-referencing syntax for the Python domain). For example,

[...] which renders as ":mod:`qdyn_grid_mod`" to refer to the
:mod:`grid <qdyn_grid_mod>` module.

from the rst code of the last bullet point above. There, the reference to qdyn_grid_mod is rendered with the text “grid”.

There is no module-scoping for :type:, :typef:, or :func:: All routines and types must have unique names across the entiry QDYN library. Sphinx will then automatically identify which module a routine is defined in. This is different from :func: in the Python domain, which may use references with a fully specified path (including modules/submodules).

Note that there is no way to reference the arguments of a routine. You should use single backticks for argument names, e.g.

[...] the `method` argument of the :func:`prop` routine.

which renders as “[…] the method argument of the prop() routine.”

Warning

In Python docstrings for the QDYN-pylib API, references to Fortran objects must be prefixed with :f, e.g. f:func:`prop` to refer to prop(), see the QDYN-pylib documentation guidelines

References to Python objects

In the main QDYN documentation, that is, any RST file or any Fortran docstrings, routines in the QDYN-pylib qdyn package can be referenced by using roles prefixed with :py, see “Cross-referencing Python objects” in the Sphinx documentation:

  • :py:mod: to reference a Python module, e.g. :py:mod:`qdyn.pulse` to reference qdyn.pulse.

  • :py:class: to reference a Python class, e.g. :py:class:`qdyn.pulse.Pulse` to reference qdyn.pulse.Pulse.

  • :py:func: to reference a Python function, e.g. :py:func:`qdyn.pulse.blackman` to reference qdyn.pulse.blackman().

You may also reference Python objects from the Python standard library or some important external Python packages (see the intersphinx_mapping in ./docs/sources/conf.py):

  • :py:class:`str` to reference the standard-library str.

  • :py:class:`qutip.Qobj` to reference qutip.Qobj.

  • :py:func:`krotov.optimize.optimize_pulses` to reference krotov.optimize.optimize_pulses().

Only within Python docstrings, the :py prefix is implicit (but, conversely, references to Fortran objects must have a :f prefix)

Warning

Use the :f prefix when referencing Fortran objects from Python docstrings, and the :py prefix when referencing Python objects from Fortran docstrings.

References to the config file

The QDYN documentation also includes a Sphinx extensions that defines a :config: role for referencing the documentation of QDYN’s config file (doc/sources/_extensions/config_roles.py).

You may reference e.g. the grid section of the config file as :config:`grid`. A key within a section may be referenced as e.g. :config:`grid:coord_type`, which renders as “grid:coord_type” to refer to the coord_type key in the grid section of the config file. To drop the section name from the rendered reference, prefix the section name with a tilde, e.g. :config:`~grid:coord_type` which renders as “coord_type”. This serves to distinguish the same key name being valid in different sections. The :config: role does not support the :role:`text <target>` syntax to change the text of the rendered label. However, you could use the :ref: role (“Cross-referencing arbitrary locations”, see below) to link the documentation for sections of the config file, e.g.

Read the :ref:`documentation for the grid section of the config file <confsec-grid>`

which would render as “Read the documentation for the grid section of the config file

References to other sections

To link to arbitrary sections in the documentation, the underlying RST file must include a reference-label immediately before the section header, as described in “Cross-referencing arbitrary locations”. If you want to link to any part of QDYN’s documentation that does not yet have a label, edit the relevant RST file to add it. Then, use the :ref: role to reference it. You can use :ref:`reflabel` to insert the section heading that the reflabel refers to, or :ref:`text <reflabel>` to use an arbitrary text (cf. the example at the end of the “References to the config file” section above.)

Note the extra leading underscore in the definition of reference labels: The label is defined as e.g. .. _reflabel:, but is referenced as e.g. :ref:`reflabel`.

A possible alternative is to link not to a particular section, but to a particular rst document, using the :doc: role. This also allows to link to the documentation of a module when the use of the :mod: role is not desirable, e.g.

For example, one module may collect all the routines operating on a
particular :doc:`data type </api/structures/def>`.

Bibliographic references

References to the Bibliography are made with the :cite: role, see Bibliographic References.

Math

Sphinx/RST has excellent built-in support for mathematics, using LaTeX-math-syntax. Inline math is done with the math-role, e.g. :math:`x^2` will render as “\(x^2\)”.

In docstrings only, you may enclose inline mathematics in dollar signs ($x^2$) instead of using the math role.

For display math (equations), use the math-directive. You have the option to use equation numbers and references, e.g.:

.. math::
    :label: EqSchrödinger

    \ii \hbar \frac{\partial}{\partial t} \ket{\Psi(t)} = \Op{H} \ket{\Psi(t)}

The Schrödinger Equation :eq:`EqSchrödinger` describes the time
evolution of a quantum state :math:`\ket{\Psi(t)}`.

This renders as:

(1)\[\ii \hbar \frac{\partial}{\partial t} \ket{\Psi(t)} = \Op{H} \ket{\Psi(t)}\]

The Schrödinger Equation (1) describes the time evolution of a quantum state \(\ket{\Psi(t)}\).

If your editor supports it, use a non-breaking space before the :eq: (<ctrl>-k <space> <space> in vim, <ctrl>-q 240 in Emacs, corresponding to ~ in LaTeX).

Equation numbers run consecutively throughout the entire documentation. Thus, you can reference equations on other pages.

The contents of the math directive should be indented with four spaces.

QDYN defines some semantic macros for quantum mechanics in the mathjax_config setting in doc/sources/conf.py. These include:

  • \ee for the Euler unit \(\ee\)

  • \ii for the imaginary unit \(\ii\)

  • \dd for the differential \(\dd\)

  • \bra{\Psi} for the \(\bra{\Psi}\) (or \Bra for a macro that adjusts height)

  • \ket{\Psi} for the \(\ket{\Psi}\) (or \Ket for a macro that adjusts height)

  • \Braket{\Psi}{\Psi} for simple bra-kets \(\Braket{\Psi}{\Psi}\)

  • \Op{H} for the operator \(\Op{H}\)

  • \norm{\Op{H}} for the norm \(\norm{\Op{H}}\) (or \Norm for a macro that adjusts height)

  • \avg{\Op{H}} for the average/expectation value \(\avg{\Op{H}}\) (or \Avg for a macro that adjusts height)

  • \Abs{x} for the absolute value \(\Abs{x}\) (not to be confused with the lower-case \abs which renders as e.g. \(\abs(x)\))

  • \AbsSq{\ket{x}} for the absolute-square \(\AbsSq{x}\)

  • \Liouville for the Liouville symbol \(\Liouville\)

  • \DynMap for the dynamical map symbol \(\DynMap\)

  • \identity for the identity \(\identity\)

  • \Complex for the set of complex numbers \(\Complex\)

  • \Real for the set of real numbers \(\Real\)

  • \Integer for the set of natural numbers \(\Integer\)

You may extend these definitions as necessary.

Warning

Use semantic macros wherever possible. Most importantly, do not set \(\ket{\Psi}\) as \vert \Psi \rangle or \(\Op{H}\) as \hat{H}. You may still use \langle, \vert, and \rangle for bra-ket expressions that \Braket cannot express accurately. Make sure to use the appropriate lower- or upper-case macro for the proper height of delimiters. In text, usually e.g. \ket should be used instead of \Ket.

Code and pre-formatted text

Enclose inline code in double backticks, e.g. ``method="cheby"``, which renders to method="cheby".

Longer code snippets use the code-block-directive, which can have syntax highlighting for any language that Pygments understands.

For example,

.. code-block:: fortran

    call cdft(2*n, 1, a, ip, w)
    do j = 0, 2 * n - 1
      a(j) = a(j) / n
    end do

renders as:

call cdft(2*n, 1, a, ip, w)
do j = 0, 2 * n - 1
  a(j) = a(j) / n
end do

If no syntax-highlighting or other advanced options are desired, .. code-block:: can be shortened to ::. Also, ending a paragraph with ::, followed by indented code will replace the double-colon with a single colon and format the code without syntax highlighting.

The content of the directive should be indented by four spaces relative to the ..code-block:: or :: (while Fortran code in QDYN is still usually indented by only two spaces, as in the above example).

Documentation Checklist

The following checklists serve as a guide when adding to or modifying any parts of the documentation.

Docstrings

Use the following checklist for the docstrings in the QDYN source code which get rendered into the API documentation. Remember that docstrings are reference material and should be written in a strictly information-oriented style. They target QDYN developers at any level. Only describe (“What?”); explanations (“Why?”) or extended usage discussion (“How?”) should be reserved for other parts of the documentation such as Topical Overviews and How-tos. The API reference documentation is generally not sufficient by itself. It must be augmented by how-to guides, examples, and topical overviews to provide broader context.

  • Module has a description that contains

    • The purpose of module

    • The organization of routines in the module to highlight the most important routines

    • If appropriate, a local list of references

  • Other parts of the documentation also cover the functionality implemented in the module. If not, open an issue that a how-to guides/example/topical overview needs to be added.

  • Every routine, type, or interface in the module is documented (even when private).

  • For every routine:

    • Description starts with a summary line that fits on one line (after !! @description: or on a new line after !! @description:)

    • Summary line ends with a period

    • Summary line is separated from subsequent paragraphs with a blank line

    • The description is accurate, complete, and understandable to a new user of QDYN, but also concise.

    • Every parameter in the function has a complete, understandable but concise docstring

    • All the parameter docstrings are aligned (except for very long parameter names, which may use a “hanging indent”)

    • All inline math is set with dollar signs and renders correctly in the HTML

    • All math uses proper domain-specific macros such as \ket

    • All references to other parameters are enclosed in single backticks

    • Values like .true. or strings are enclosed in single backticks

    • Other expressions that should be rendered as code are enclosed in double backticks

    • Any references to other modules, other routines or config file options use the proper role and link correctly in the rendered HTML.

    • Code-blocks are set correctly with an RST ..code-block:: directive, and use syntax highlighting if appropriate

  • Check the rendered HTML documentation for the module API

    • Sphinx reports no errors

    • All hyperlinks resolve correctly in the rendered HTML

    • All equations render properly in MathJax

    • Bibliographic entries link properly to the main References page

    • The summary table is readable and provides a useable overview

    • If the docstring is for a *_pt data structure, check the Config File reference documentation to ensure that it reads well and that any examples render properly.

How-Tos

Use the following checklist when writing how-tos. Remember that how-tos are intended to be goal-oriented: A user knows what they want to do, but not how. How-to guides should be written as RST documents, not Jupyter notebooks. This encourages conciseness: how-to guides (unlike example notebooks) are generally not complete examples, and skip the setup or analysis of an example.

  • Targets a user with basic familiarity of QDYN and the underlying physics

  • Written as an RST document

  • Title starts with “How To”

  • Solves a particular problem or addresses a specific question or concern (an “FAQ”)

  • Focuses on achieving a practical goal

  • Contains a list of steps that need to be followed in order

  • As short a possible

  • Does not explain concepts or design decisions. These should be written as topical overviews.

  • Discusses different options for solving a problem and their relative trade-offs

  • Provides example code snippets but not full examples

  • Check the rendered how-to in the HTML documentation to ensure proper formatting.

Examples

Use the following checklist when writing example notebooks. Remember that examples are learning-oriented. They should teach a novice user a possible usage of QDYN in a particular context. Ideally, most papers written using QDYN should be worked into a tutorial. However, when writing a tutorial from a published paper or thesis, simplify the example as much as possible to make it more accessible. Examples must be written as a Jupyter notebook to ensure that the example is complete, reproducible, and provides immediate feedback.

  • Targets a beginner with only basic familiarity of QDYN (the introductory tutorial) and the underlying physics

  • Written as a Jupyter notebook.

  • Includes a citation of the paper from which the example is derived

  • Self-contained: must render correctly on https://nbviewer.jupyter.org

  • Includes relevant equations, e.g. the system Hamiltonian, using semantic tex macros

  • As simple and accessible as possible

  • Uses high-level tools as much as possible, e.g. QuTiP/qdynpylib to set up the problem, qdyn_proj_traj and qdyn_optimize to perform propagation and optimization.

  • Visualizes results with matplotlib

  • Does not explain anything that is not absolutely necessary to follow the tutorial.

  • Avoids discussions of alternative approaches as much as possible.

  • Check the rendered example in the HTML documentation to ensure proper formatting.

Topical Overviews

Use the following checklist when writing topical overviews. Remember that topical overviews are understanding-oriented explanations. Topical overviews collect the in-depth knowledge around the development and usage of QDYN. It is intended to transfer knowledge to future generations of students. Compared to a published review paper or thesis, topical overviews are living documents that can keep up with new developments. The QDYN documentation does need many topical overviews, but those that exist should be written to the highest possible standard. The overviews should take a high-level view and strive for completeness. A comparative overview of all propagation methods is preferable to an overview of just one single method. Thus, they will tend to be relatively long and contain sub-sections. Topical overviews can be opinionated. They should capture expert developer experience. They may have a narrative component of how QDYN evolved over time.

  • Targets a user with a good understanding of QDYN and the underlying physics

  • Written as an RST document

  • Contains in-depth explanations of numerical methods, including full derivations, at the level of a published review paper or thesis chapter

  • Documents design decisions for data structures and methods in QDYN.

  • Extensively cites existing literature

  • Avoids examples or usage guidelines. These are better written as example notebooks or how-to guides.

  • May extend beyond QDYN, e.g. comparing with other tools and methods

  • Check the rendered HTML documentation to verify that math is rendered correctly and bibliographic references resolve to the References page.