The Octopus documentation web pages are written in markdown and
use Hugo as framework with the hugo-theme-docdock theme.
Hugo is a static webpage generator, which builds web pages from markdown sources.
For the Octopus pages, we keep these markdown sources within the Octopus source repository, which should encourage to write documentation whenever new code is added, and to update the documentation in case of code changes. The remaining files (e.g. configuration, shortcodes) required for the Hugo system reside in a separate repository.
The header
Hugo requires a header on each page, which contains metadata about the page. Let’s have a look at this example:
---
title: "Getting started"
description: "Learn how to run the code"
weight: 1
tutorials: ["Octopus Basics"]
theories: ["DFT"]
calculation_modes: ["Ground state"]
system_types: ["Molecule"]
species_types: ["Pseudopotentials"]
features: ["Total energy"]
utilities: []
difficulties: ["basic"]
---
The minimum required header must contain:
---
title: "Getting started"
---
Without these lines, a page will not be rendered to HTML.
The description should be a one-line summary of the page, and weight determines the order, in which pages are displayed in listings, with smaller number being displayed first.
The remaining entries are part of the so-called taxonomy, and are used to assign pages to certain categories. See Tutorials as example.
Hugo shortcodes
Hugo provides so-called shortcodes, which allow to define functions or macros, which can be used on a markdown page.
{{< octopus >}}: Octopus
{{< octopus-version >}}: 15
{{< emph "text" >}}: text
{{< code "text" >}}: text
{{< code-line "text" >}}: text
{{< file "text" >}}: text
{{< command "text" >}}: text
{{< command-line "text" >}}:
text
{{< name "text" >}}: text
Some of these seem redundant, but they originate from porting the old wikimedia pages to the new framework.
Shortcodes as those above receive any content as argument. This, however, does not allow to render further markup or other shortcodes inside this content.
If this is required, one has to use shortcodes which come as a opening and closing shortcode. Some examples for these are:
Inline code:
An inline code segment like {{< code-inline >}}This is version {{< octopus-version >}}{{< /code-inline >}} will display the
text This is version 15 inline with the paragraph.
Other usful shortcodes:
Units
{{< angstrom >}}: Å
{{< bohr >}}: b
{{< hartree >}}: Ha
Compilation
{{< cc >}}: <cc>
{{< cflags >}}: <cflags>
{{< f90 >}}: <f90>
{{< fcflags >}}: <fcflags>
{{< basedir >}: <basedir>
Automatically generated pages
The information about the variables is automatically generated from the source code.
Versioning of the documentation
The Hugo system, together with the scripts to build the pages, can provide the documentation for different (major) versions of Octopus.
If, for a given branch of the code, the documentation is contained in the folder <basedir>/doc/hugo/
, the contents of these folders will be copied into the Hugocontent/
folder, before the pages for that version are created. If this directory does not exist, the files will be taken from default_content/
within the octopus documentation repository.
Version dependent content
In general, content which is only for given versions of Octopusshould be organized through including the documentation in the Octopus repository.
In case, version dependent content has to be added for older branches, which do not have the documentation in the code repository, there are the shortcodes:
In order to create links to sections of the manual or tutorial, which refer to the correct Octopus version, the following shortcodes are provided:
{{< manual "Section:Name" "display text" >}}: create a link to a manual page
{{< tutorial "Section:Name" "display text" >}}: create a link to a tutorial page
{{< developers "Section:Name" "display text" >}}: create a link to a developers page
{{< variable "VariableName" >}}: create a link to a variable reference
{{< versioned-link "page address" "display text" >}}: create a link to a page, where the address is relative to the top page of a given version.
Including input files
Due to some limitations of Hugo, we cannot use shortcodes to include input files into a markdown file. Instead, this is handled by a shell script ( build-pages.sh), which preprocesses markdown files, and inserts annotated input file. In a markdown file we can use
#include_input filename
where filename includes the path, relative to the Octopus<basedir>.
This command copies the file from the Octopus source tree into the hugo folders, and also annotates the file, i.e. is replaces all occurances of known variable names by the {{< variable "VariableName" >}}, which produces a link to the corresponding variable reference.
### Including input file snippets
In addition to complete input files, it is also possible to include a section, or snippet, of an input file.
The syntax is similar to the above, but uses the macro {<>}, as demonstrated in the following example:
This requires the markers "#snippet_startname" and "#snippet_endname"
in the input file. Due to the leading '#'. Octopus treats them as comments and ignores those markers.
Similar to the above macros to include some testfiles, there is also a macro to include the definition block of some user defined types.
Using
#include_type_def <typename>
extracts the corresponding source lines from the correct version of the code and inserts them into the markdown file, before further processing.
Note that no comments after the type name are allowed in the Fortran source. Otherwise the extraction preprocessor does not recognise the line.
To also use the Fortran source highlighting of Hugo it is best to sandwich that by
```Fortran
```
Example
The following markdown excerpt
{{% expand "click to expand the definition of batch_t" %}}
```Fortran
#include_type_def batch_t
```
{{% /expand %}}
will generate the following result:
click to expand the definition of batch_t
typebatch_tprivateinteger,public::nst!< number of functions in the batch
integer,public::dim!< Spinor dimension of the state (one, or two for spinors)
integer::np!< number of points in each function (this can be np or np_part)
integer::ndims!< The second dimension of ist_idim_index(:,:). Currently always set to 2.
integer,allocatable::ist_idim_index(:,:)!< @brief index mapping fom global (ist,idim) to local ist.
!!
!! This maps ist and idim into one linear array.
!! This index is constructed in batch_oct_m::batch_build_indices
integer,allocatable,public::ist(:)!< @brief map from an global to local index
!!
!! The global index does not need to start at 1, while
!! the local index is always in the range 1:nst.
!!
!! This index is constructed in batch_oct_m::batch_build_indices
logical::is_allocated!< indicate allocation status
logical::own_memory!< does the batch own the memory or is it foreign memory?
! We also need a linear array with the states in order to calculate derivatives, etc.
integer,public::nst_linear!< nst_linear = nst * st%d%dim
integer::status_of!< @brief packing status of the batch
!!
!! possible values are:
!! BATCH_NOT_PACKED, BATCH_PACKED, BATCH_DEVICE_PACKED
integer::status_host!< @brief packing status in CPU memory
!!
!! If Octopus runs on GPU, this indicates the status on the CPU.
!! It can only be BATCH_NOT_PACKED and BATCH_PACKED.
!! This makes transfers more efficient: usually we allocate a
!! batch as packed on the CPU, then call do_pack to copy it to the GPU.
!! In this case, it is really a copy.
!! If the batch is unpacked on the CPU, we need to transpose in
!! addition which makes it much slower.
type(type_t)::type_of!< either TYPE_FLOAT or TYPE_CMPLX
integer::device_buffer_count!< keep track of pack operations performed on the device
integer::host_buffer_count!< keep track of pack operations performed on the host
logical::special_memory!< are we using hardware-aware memory?
logical::needs_finish_unpack!< if .true., async unpacking has started and needs be finished
! unpacked variables; linear variables are pointers with different shapes
real(real64),pointer,contiguous,public::dff(:,:,:)!< pointer to real mesh functions: indices are (1:np, 1:dim, 1:nst)
complex(real64),pointer,contiguous,public::zff(:,:,:)!< pointer to complex mesh functions: indices are (1:np, 1:dim, 1:nst)
real(real64),pointer,contiguous,public::dff_linear(:,:)!< pointer to real mesh functions: indices are (1:np, 1:nst_linear)
complex(real64),pointer,contiguous,public::zff_linear(:,:)!< pointer to complex mesh functions: indices are (1:np, 1:nst_linear)
! packed variables; only rank-2 arrays due to padding to powers of 2
real(real64),pointer,contiguous,public::dff_pack(:,:)!< pointer to real mesh functions: indices are (1:nst_linear, 1:np)
complex(real64),pointer,contiguous,public::zff_pack(:,:)!< pointer to complex mesh functions: indices are (1:nst_linear, 1:np)
integer(int64),public::pack_size(1:2)!< pack_size = [pad_pow2(nst_linear), np]
!! (see math_oct_m::pad_pow2)
integer(int64),public::pack_size_real(1:2)!< pack_size_real = pack_size;
!! if batch type is complex, then
!! pack_size_real(1) = 2*pack_size(1)
type(accel_mem_t),public::ff_device!< pointer to device memory
containsprocedure::check_compatibility_with=>batch_check_compatibility_with!< @copydoc batch_oct_m::batch_check_compatibility_with
procedure::clone_to=>batch_clone_to!< @copydoc batch_oct_m::batch_clone_to
procedure::clone_to_array=>batch_clone_to_array!< @copydoc batch_oct_m::batch_clone_to_array
procedure::copy_to=>batch_copy_to!< @copydoc batch_oct_m::batch_copy_to
procedure::copy_data_to=>batch_copy_data_to!< @copydoc batch_oct_m::batch_copy_data_to
procedure::do_pack=>batch_do_pack!< @copydoc batch_oct_m::batch_do_pack
procedure::do_unpack=>batch_do_unpack!< @copydoc batch_oct_m::batch_do_unpack
procedure::finish_unpack=>batch_finish_unpack!< @copydoc batch_oct_m::batch_finish_unpack
procedure::end=>batch_end!< @copydoc batch_oct_m::batch_end
procedure::inv_index=>batch_inv_index!< @copydoc batch_oct_m::batch_inv_index
procedure::is_packed=>batch_is_packed!< @copydoc batch_oct_m::batch_is_packed
procedure::ist_idim_to_linear=>batch_ist_idim_to_linear!< @copydoc batch_oct_m::batch_ist_idim_to_linear
procedure::linear_to_idim=>batch_linear_to_idim!< @copydoc batch_oct_m::batch_linear_to_idim
procedure::linear_to_ist=>batch_linear_to_ist!< @copydoc batch_oct_m::batch_linear_to_ist
procedure::pack_total_size=>batch_pack_total_size!< @copydoc batch_oct_m::batch_pack_total_size
procedure::remote_access_start=>batch_remote_access_start!< @copydoc batch_oct_m::batch_remote_access_start
procedure::remote_access_stop=>batch_remote_access_stop!< @copydoc batch_oct_m::batch_remote_access_stop
procedure::status=>batch_status!< @copydoc batch_oct_m::batch_status
procedure::type=>batch_type!< @copydoc batch_oct_m::batch_type
procedure::type_as_int=>batch_type_as_integer!< @copydoc batch_oct_m::batch_type_as_integer
procedure,private::dallocate_unpacked_host=>dbatch_allocate_unpacked_host!< @copydoc batch_oct_m::dbatch_allocate_unpacked_host
procedure,private::zallocate_unpacked_host=>zbatch_allocate_unpacked_host!< @copydoc batch_oct_m::zbatch_allocate_unpacked_host
procedure,private::allocate_unpacked_host=>batch_allocate_unpacked_host!< @copydoc batch_oct_m::batch_allocate_unpacked_host
procedure,private::dallocate_packed_host=>dbatch_allocate_packed_host!< @copydoc batch_oct_m::dbatch_allocate_packed_host
procedure,private::zallocate_packed_host=>zbatch_allocate_packed_host!< @copydoc batch_oct_m::zbatch_allocate_packed_host
procedure,private::allocate_packed_host=>batch_allocate_packed_host!< @copydoc batch_oct_m::batch_allocate_packed_host
procedure,private::allocate_packed_device=>batch_allocate_packed_device!< @copydoc batch_oct_m::batch_allocate_packed_device
procedure,private::deallocate_unpacked_host=>batch_deallocate_unpacked_host!< @copydoc batch_oct_m::batch_deallocate_unpacked_host
procedure,private::deallocate_packed_host=>batch_deallocate_packed_host!< @copydoc batch_oct_m::batch_deallocate_packed_host
procedure,private::deallocate_packed_device=>batch_deallocate_packed_device!< @copydoc batch_oct_m::batch_deallocate_packed_device
endtypebatch_t
Note that the
```Fortran
```
construction only works if the expand is given in the form {{% expand ... %}} ... {{% /expand %}}. The
variant {{< expand ... >}} ... {{< /expand >}} does not work.
Including code snippets
Finally, there is a macro to include a general code snipped, which has to be marked in the source code as follows:
...!# doc_start <name>
somecode...!# doc_end
Using
```Fortran
#include_code_doc <name>
```
extracts the corresponding source lines from the correct version of the code and inserts them into the markdown file, before further processing.
Including mathematical formulas
The Hugo framework to generate the pages is set up to use katex to render mathematical formulas. The headers, which are silently included
in every page contain scripts, which enable the rendering of formulas, typeset in LaTeX. Further information about katex can be found here.
In short, most LaTeX formulas can be inserted, either inline, enclosed by single ‘$’ characters, or as separate lines, using double ‘$$’s.
Examples
The density is defined by $n({\bf r}) = \sum_i |\varphi_i({\bf r})|^2$, where the wavefunctions obey
$$
\left( -\frac{\nabla^2}{2 m} + v({\bf r}) \right) \varphi_i({\bf r}) = \epsilon_i \varphi_i({\bf r}) .
$$
The density is defined by $n({\bf r}) = \sum_i |\varphi_i({\bf r})|^2$, where the wavefunctions obey
$$
\left( -\frac{\nabla^2}{2 m} + v({\bf r}) \right) \varphi_i({\bf r}) = \epsilon_i \varphi_i({\bf r}) .
$$
In some cases, the equations do not render correctly. In this cases, it might be necessary to escape some control characters (mainly the underscore) by an extra backslash.
For further details, see e.g. this web page