Documentation#
The package documentation is provided under acoular/docs/source. This directory contains the index.rst file which serves as the root document (landing page) embedding several other subdocuments (sub-pages) written in reStructuredText format.
The full documentation is built using the Sphinx package. See Documentation Compilation for instructions on how to build the documentation locally.
Attention
Some of the subdirectories (sub-pages) are created automatically during the documentation build process. Therefore, the generated files should not be edited directly.
This mainly concerns the docs/source/api_ref/generated directory, which contains the API documentation generated from the source code, and the docs/source/auto_examples directory, which contains the auto-generated examples.
User Documentation#
This is the easiest way to contribute to the documentation. You can simply edit the corresponding .rst files in the acoular/docs/source directory which are not generated automatically. Make sure you are using the reStructuredText format. If you want to add a new document, it should be referenced in the index.rst or any related file. We are happy about every fixed spelling mistake or improved explanation.
Documenting the API#
There are several situations in which you want to change the API documentation. For example, when you add a new class, method, or function, or when you change the signature of an existing method. In some cases, you might also want to improve the existing documentation.
The API documentation is generated from the documentation strings of the source code using the Sphinx autosummary extension. The API documentation follows the NumPy style.
The generated API documentation can be found in the source/api_ref subdirectory of the documentation after compilation.
Documenting Classes, Methods and Functions#
We will take a look at the TimeSamples class as an example of how a class docstring should look like.
Writing docstrings:
Docstrings should first contain a short summary line, followed by an extended summary using reStructuredText syntax. An extended summary is not always necessary, but it is recommended not only for complex implementations. Ideally, the extended summary provides a detailed explanation of the method’s purpose, behaviour, and usage.
class TimeSamples(SamplesGenerator):
"""
Container for processing time data in ``*.h5`` or NumPy array format.
The :class:`TimeSamples` class provides functionality for loading, managing, and accessing
time-domain data stored in HDF5 files or directly provided as a NumPy array. This data can be
accessed iteratively through the :meth:`result` method, which returns chunks of the time data
for further processing.
Cross-references can be included in the See Also section, which lists related classes or functions:
See Also
--------
:class:`~acoular.sources.MaskedTimeSamples` :
Extends the functionality of class :class:`TimeSamples` by enabling the definition of start
and stop samples as well as the specification of invalid channels.
Additional information can be included in a dedicated Notes section. The Notes section can then also be cross-referenced in other parts of the documentation.
Notes
-----
- Metadata from the :attr:`HDF5 file<file>` can be accessed through the :attr:`metadata`
attribute.
We welcome the addition of code examples to the docstrings of classes (and functions). The TimeSamples class provides a short snippet with explanation in the docstring:
Examples
--------
Data can be loaded from a HDF5 file as follows:
>>> from acoular import TimeSamples
>>> file = <some_h5_file.h5> # doctest: +SKIP
>>> ts = TimeSamples(file=file) # doctest: +SKIP
>>> print(f'number of channels: {ts.num_channels}') # doctest: +SKIP
number of channels: 56 # doctest: +SKIP
Alternatively, the time data can be specified directly as a NumPy array. In this case, the
:attr:`data` and :attr:`~acoular.base.Generator.sample_freq` attributes must be set manually.
>>> import numpy as np
>>> data = np.random.rand(1000, 4)
>>> ts = TimeSamples(data=data, sample_freq=51200)
Chunks of the time data can be accessed iteratively via the :meth:`result` generator. The last
block will be shorter than the block size if the number of samples is not a multiple of the
block size.
>>> blocksize = 512
>>> generator = ts.result(num=blocksize)
>>> for block in generator:
... print(block.shape)
(512, 4)
(488, 4)
"""
To ensure that the code-snippets in the Examples section stay up-to-date, they are tested automatically in Acoular’s CI workflow using pytest with the python standard doctest module. This requires that the code examples are written in a way that they can be executed as standalone code snippets. In very rare cases, it is not possible to write an executable standalone code snippet. In such cases, the code snippet can be marked with the # doctest: +SKIP directive to be excluded from the doctests.
One can use the following command to run the doctests locally:
$ uv run python -m pytest --doctest-modules acoular
$ python -m pytest --doctest-modules acoular
$ python -m pytest --doctest-modules acoular
$ python -m pytest --doctest-modules acoular
Documenting class attributes:
Acoular makes use of the Traits package, which allows for the definition of class attributes with type checking and default values. Most of the Acoular classes will directly define their attributes, and the corresponding __init__ method will not be explicitly defined. It is recommended to document public class attributes using a comment line above the attribute definition starting with #:. Sphinx will automatically detect these comments and include them in the API documentation.
Note
The traits.traits.Trait-inherited classes have a desc attribute for trait description. In order to avoid clutter, this attribute should not be used and the Sphinx comment docstring with #: should be used instead.
Documenting public methods and functions:
Similar to classes, public methods and functions need to have a docstring. In addition to the summary line, the arguments and return values should be documented in NumPy style.
See the result() generator as an example:
def result(self, num=128):
"""
Generate blocks of time-domain data iteratively.
The :meth:`result` method is a Python generator that yields blocks of time-domain data
of the specified size. Data is either read from an HDF5 file (if :attr:`file` is set)
or from a NumPy array (if :attr:`data` is directly provided).
Parameters
----------
num : :class:`int`, optional
The size of each block to be yielded, representing the number of time-domain
samples per block.
Yields
------
:class:`numpy.ndarray`
A 2D array of shape (``num``, :attr:`num_channels`) representing a block of
time-domain data. The last block may have fewer than ``num`` samples if the total number
of samples is not a multiple of ``num``.
Raises
------
:obj:`OSError`
If no samples are available (i.e., :attr:`num_samples` is ``0``).
Autosummary:
To ensure that a new class, or function is included in the generated API documentation, it needs to be added to the .. autosummary:: section at the top of the respective Python module file so that it can be recognized by Sphinx.
.. autosummary::
:toctree: generated/
TimeSamples
MaskedTimeSamples
PointSource
PointSourceDipole
SphericalHarmonicSource
LineSource
MovingPointSource
MovingPointSourceDipole
MovingLineSource
UncorrelatedNoiseSource
SourceMixer
PointSourceConvolve
spherical_hn1
get_radiation_angles
get_modes
The .. autosummary:: section contains a list of the classes, functions, and constants defined in the module.
Documenting Modules#
Module files need a Copyright header and should be documented with a module docstring at the beginning of the file. The docstring should contain a summary of the module’s purpose. The docstring should be enclosed in triple quotes and should be placed at the beginning of the file, before any other code. It may contain .. inheritance-diagram:: and .. autosummary:: directives.
Writing Python examples#
Acoular provides a set of examples that demonstrate how to use the package. These examples are located in the acoular/examples subdirectory.
We are always looking for new examples that demonstrate the functionality of Acoular. If you have a good example that you would like to share, please consider contributing it to the Acoular package.
We also encourage you to enhance the existing examples by adding more detailed explanations, improving the code, or adding new features.
We use the Sphinx-Gallery extension to automatically generate .rst files and downloadable Notebooks in .ipynb format from the Python examples. During the build process, the generated files will be written into the docs/source/auto_examples directory.
Adding new examples#
To add a new example, create a new Python script in one of the subdirectories of the examples directory.
If no subdirectory is suitable, you can create a new one.
The name of the script should start with example_ followed by a short descriptive name.
In case of the latter, make sure to add the new subdirectory in the acoular/docs/source/conf.py file to the sphinx_gallery_conf dictionary:
sphinx_gallery_conf = {
...
'subsection_order' : ExplicitOrder([
"../../examples/introductory_examples",
"../../examples/wind_tunnel_examples",
"../../examples/moving_sources_examples",
"../../examples/io_and_signal_processing_examples",
"../../examples/tools",
"<ADD YOUR NEW SUBDIRECTORY HERE>"
]),
}
All examples are executed during the documentation build process to ensure that they are working correctly. Therefore, it is important to keep an eye on the execution time of your example. We can only accept examples that run in a reasonable time (ideally within a few seconds).
Citing literature#
If you are adding a new feature or method that is based on scientific literature, please make sure to include the corresponding references as a bibtex entry in the acoular/docs/source/literature/literature.bib file. Details on the bibtex format can be found here.
You can then cite the reference using the directive :cite:`<BIBTEX_KEY>` directive in the documentation. Your citation will be automatically included in the bibliography section of the documentation.