Writing tutorials#

You can improve the PyDPF-Core documentation by adding a:

To do so, you must follow the guidelines presented here.

Tutorials are Python scripts processed by sphinx-gallery and live in the doc/sphinx_gallery_tutorials/ directory. During the build, sphinx-gallery automatically converts them to HTML pages, Jupyter notebooks, and downloadable Python scripts. Manual toctree entries are only needed in the doc/sphinx_gallery_tutorials/index.rst file to link the section landing pages, but not for individual tutorials. sphinx-gallery manages the toctree for individual tutorials.

You also need to understand the structure of the doc directory on the PyDPF-Core library:

.
├── doc
│   ├── sphinx_gallery_tutorials
│   │   ├── index.rst                <- Tutorials landing page
│   │   └── section_name
│   │       ├── GALLERY_HEADER.rst   <- Section landing page
│   │       └── tutorial_name.py     <- Tutorial script
│   ├── source
│   │    ├── api
│   │    ├── tutorials               <- Auto-generated by sphinx-gallery
│   │    ├── examples                <- Auto-generated by sphinx-gallery
│   │    ├── getting_started
│   │    ├── images
│   │    ├── user_guide
│   │    ├── conf.py
│   │    ├── index.rst
│   ├── styles
│   ├── make.bat

Tutorials source files are in doc/sphinx_gallery_tutorials. The doc/source/tutorials directory is auto-generated and must not be edited by hand.


Adding a new tutorial section#

Download the new tutorial section template

Note

Avoid creating new sections unless absolutely necessary. When in doubt, mention the intended location in the pull request for approval. Every section folder must contain a GALLERY_HEADER.rst file as the documentation ignores folders that lack this file.

Location and naming#

The new tutorial section must reside in a new folder such as doc/sphinx_gallery_tutorials/new_section_name.

.
├── doc
│   ├── sphinx_gallery_tutorials
│   │    ├── new_section_name

Structure#

The section folder must contain a GALLERY_HEADER.rst file with:

  • a reference label for cross-referencing this section from other parts of the documentation,

  • a section title,

  • a general description of the topics covered in the tutorials in this section,

  • grid cards with links, titles, and descriptions for the tutorials in the section.

.. _ref_tutorials_new_section_name:

=================
New section title
=================

Description of what the tutorials in this section cover.

.. grid:: 1 1 3 3
    :gutter: 2
    :padding: 2
    :margin: 2

    .. grid-item-card:: Tutorial title
       :link: ref_tutorial_name
       :link-type: ref
       :text-align: center

       This tutorial ...

.. raw:: html

   <style>.sphx-glr-thumbnails { display: none; }</style>

You must add a card linking to the new section in the top-level doc/sphinx_gallery_tutorials/index.rst, following the same .. grid-item-card:: pattern as the existing sections; and you must also add a toctree entry for the new section to the same file following the same tutorials/<section-name>/index.rst pattern as the existing toctree entries.


Adding a new tutorial#

Download the tutorial card template Download the tutorial structure template Download the tutorial content formatting template

Location and naming#

New tutorials are Python .py files in the corresponding tutorial section folder, for example: doc/sphinx_gallery_tutorials/section_name/new_tutorial.py

.
├── doc
│   ├── sphinx_gallery_tutorials
│   │    ├── section_name
│   │    │    ├── new_tutorial.py

You must also add a card to the section’s GALLERY_HEADER.rst. The card must include:

  • a tutorial title,

  • a short description (same as the goal sentence in the tutorial file itself),

  • a link to the tutorial’s reference label.

Structure#

The tutorial file is divided in two main parts:

Content cells#

The goal of a tutorial is to present a feature or explain how to perform a common task step by step while explaining behaviors or underlying concepts. Thus, its structure must prioritize clarity, simplicity, and logical flow.

After the module docstring, the tutorial is organized as a series of cells separated by a line of exactly 79 # characters (###...###). Each cell is either a text cell (consecutive # ``-prefixed comment lines, full RST supported) or a **code cell** (executable Python lines). A cell separator followed by ``# Title / # ----- comment lines renders as an RST section heading in the output HTML.

The content steps are generally:

  1. A first step where you get some data and create DPF objects based on the data;

  2. One or more steps where you manipulate the data or the DPF objects;

  3. A final step where you reach the objective of the tutorial and obtain the expected result.

For example:

A tutorial explains how to plot a mesh using PyDPF-Core. The steps to achieve this task are:

  1. Import a result file;

  2. Extract the mesh;

  3. Plot the mesh.

To create a section heading, write the separator followed by the title and underline using ``# ``-prefixed comment lines:

###############################################################################
# Import result file
# ------------------
#
# First, you ...

###############################################################################
# Extract the mesh
# ----------------
#
# Then, you extract ...

###############################################################################
# Plot the mesh
# -------------
#
# Finally, you plot ...

Code blocks#

The tutorials must have code cells where you show how the task is actually implemented. In addition to the guidelines presented here, you must also follow the Coding style guide to ensure that all code looks the same across the project.

  • Executable code in tutorials is plain Python. There is no special directive; code cells are simply the lines of the file that are not prefixed with #:

Correct

# This is a code cell (plain Python)
from ansys.dpf import core as dpf

Incorrect

.. jupyter-execute::

    # This is a jupyter-execute block (old format)
    from ansys.dpf import core as dpf
  • Use comments within a code block to clarify the purpose of a line:

Correct

# Define the model
my_model = dpf.Model(data_sources=ds)

# Get the stress results
stress_fc = my_model.results.stress.eval()

Incorrect

model = dpf.Model(data_sources=ds)
stress_fc = model.results.stress.eval()
  • Split code into separate cells using the ###...### separator to include longer text explanations or to force showing an intermediate output:

Correct

###############################################################################
# Step 1
# ------
#
# Explanation for a first code cell

# Code comment 1
code1

###############################################################################
# Step 2
# ------
#
# Explanation for a second code cell

# Code comment 2
code2

Incorrect

###############################################################################
# Step 1 and 2
# -------------
#
# A single broad explanation for both steps.

# Code comment 1
code1

# Code comment 2
code2
  • When using a PyDPF-Core object or method you must name arguments:

Correct

# Get the stress results
stress_fc = model.results.stress(time_scoping=time_steps).eval()

Incorrect

# Get the stress results
stress_fc = model.results.stress(time_steps).eval()
  • When quoting APIs in the code comments you must always use their scripting name. Mind the use of a capital letter to name the DPF objects

Correct

# Define the DataSources object
ds = dpf.DataSources()

Incorrect

# Define the data sources object
ds = dpf.DataSources()
# Define the Data Sources object
ds = dpf.DataSources()
  • Use blank lines between code lines for better clarity.

Correct

# Define the result file path
result_file_path_1 = dpf.core.examples.find_simple_bar()

# Define the DataSources object
ds_1 = dpf.DataSources(result_path=result_file_path_1)

# Create a Model
my_model_1 = dpf.Model(data_sources=ds_1)

# Get the stress results
stress_fc = my_model_1.results.stress.eval()

Incorrect

# Define the result file path
result_file_path_1 = dpf.core.examples.find_simple_bar()
# Define the DataSources object
ds_1 = dpf.DataSources(result_path=result_file_path_1)
# Create a Model
my_model_1 = dpf.Model(data_sources=ds_1)
# Get the stress results
stress_fc = my_model_1.results.stress.eval()
  • Avoid naming the variables with the same name as an argument or an API. You can get inspiration from the tutorials available at Tutorials.

Correct

# Define the result file path
result_file_path = dpf.core.examples.find_simple_bar()

# Define the DataSources object
ds = dpf.DataSources(result_path=result_file_path)

# Create a Model
my_model = dpf.Model(data_sources=ds)

Incorrect

# Define the result file path
result_path = dpf.core.examples.find_simple_bar()

# Define the DataSources object
data_sources = dpf.DataSources(result_path=result_path)

# Create a Model
model = dpf.Model(data_sources=data_sources)

Text formatting#

In addition to the guidelines presented here, you must also follow the Documentation style guide to ensure that the tutorials follow a coherent writing style across the project.

Text in tutorials is written as ``# ``-prefixed RST comment lines inside text cells.

  • When quoting APIs in the text you must always use a reference to redirect it to the API reference:

Correct

# Here we use the |MeshedRegion| substitution text.

Rendered text:

Here is some text. Here we use the MeshedRegion substitution text

Incorrect

# Here we do not use the MeshedRegion substitution text.

Rendered text:

Here is some text. Here we do not use the MeshedRegion substitution text

  • Use bullet lists when enumerating items:

Correct

# This operator accepts as arguments:
#
# - A Result
# - An Operator
# - A FieldsContainer

Incorrect

# This operator accepts a Result, an Operator or a
# FieldsContainer as arguments.
  • Use a numbered list for ordered items:

Correct

# To extract the mesh you need to follow those steps:
#
# #. Get the result file;
# #. Create a Model;
# #. Get the MeshedRegion.

The #. inside a text cell renders as a numbered list.

Incorrect

# To extract the mesh you need to follow those steps:
#
# - Get the result file;
# - Create a Model;
# - Get the MeshedRegion.
  • If you need to develop explanations for each item of the list, first, enumerate and reference them. Then, explore each of them separately in sub headings.

Correct

###############################################################################
# Section title
# -------------
#
# This section presents two items:
#
# - :ref:`Item 1 <ref_tutorial_name_item_1>`
# - :ref:`Item 2 <ref_tutorial_name_item_2>`
#
# .. _ref_tutorial_name_item_1:
#
# Item 1
# ^^^^^^
#
# Presentation of the first item...

# Code for item 1

###############################################################################
# .. _ref_tutorial_name_item_2:
#
# Item 2
# ^^^^^^
#
# Presentation of the second item...

# Code for item 2

Incorrect

###############################################################################
# Section title
# -------------
#
# This section presents two items:
#
# - Item 1
# - Item 2
#
# Item 1
# ^^^^^^
# Presentation of the first item...

# Code for item 1

# Item 2
# ^^^^^^
# Presentation of the second item...