diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index 9760eef..f64e05b 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -27,10 +27,10 @@ jobs: with: python-version: "3.11" - - name: Install docs dependencies + - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r docs-requirements.txt + pip install -r requirements.txt -r docs/requirements.txt - name: Build Sphinx docs run: ./build-docs.sh diff --git a/README.md b/README.md index 5e72f47..c5b424b 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,32 @@ The documentation follows the [Diataxis approach](https://diataxis.fr/). ## Building the Docs -1. Create a virtual environment and activate it. -2. Install the requirements with `pip install -r docs-requirements.txt`. -3. Create a new branch. The main branch is protected so you can't push to it directly. -4. Build the docs locally with `./build-docs.sh`. The new version is available in `docs/build/html/index.html`. -5. When the local version looks good, push your changes and make a pull request. Pushes to main will build and deploy the new version. +1. Clone the repository +2. Create a virtual environment and activate it. +3. Install the requirements with `pip install -r requirements.txt -r docs/requirements.txt`. +4. Create a new branch. The main branch is protected so you can't push to it directly. +5. Build the docs locally with `./build-docs.sh`. The new version is available in `docs/build/html/index.html`. +6. When the local version looks good, push your changes and make a pull request. Pushes to main will build and deploy the new version. For the notebooks it is necessary to have the required pyAML packages installed in the environment. -If you add a new dependency remember to also add it in the requirements.txt or it will not be built correctly. +If you add a new dependency remember to also add it in the `docs/requirements.txt` or it will not be built correctly. -## Where to Place Content +## Developing Content Content should be placed in these categories: #### [Tutorials](https://diataxis.fr/tutorials/) A tutorial is a practical activity where learning is done by doing something meaningful towards an achievable goal. -The purpose is not to get something done but to help to learn. +The purpose is not to get something done but to help to learn. It should be structured as a lesson. The recommended format is to use a Jupyter notebook. -It should be structured as a lesson. The recommended format is to use a Jupyter notebook. +The tutorials are rendered using `sphinx-gallery`. They need to be written as a `.py` file using `rst` and not directly as Jupyter notebooks. You can use `jupytext` to make the workflow easier. -#### [How-to guides](https://diataxis.fr/how-to-guides/) +Jupytext can be used in the terminal but if you are using an IDE there are extensions available which makes it easier. In VS Code install `Jupytext for Notebooks (congyiwu)`. You should then be able to right click on a `.py` file and choose `Open as a Jupyter Notebook`. You can run and modify the notebook as normal and the changes should happen in the `.py` automatically. Just remember that `sphinx-gallery` requires `rst` while notebooks use `markdown` so comments might not be rendered exactly the same. + +To create a new tutorial you can start to write it as a notebook and then use the functionality to convert to `.py`. If you have written comments as markdown you need to manually convert them to `rst`. + +#### [How-to Guides](https://diataxis.fr/how-to-guides/) How-to guides help to get something done in the correct and safe way. The focus should be on how to achieve a specific task. @@ -32,7 +37,7 @@ The focus should be on how to achieve a specific task. Details of the difference between tutorials or how-to guides can be found at https://diataxis.fr/tutorials-how-to/#tutorials-how-to if you are unsure where to place your content. -#### [Technical reference](https://diataxis.fr/reference/) +#### [Technical Reference](https://diataxis.fr/reference/) Technical references are technical descriptions of the software, for example the API. diff --git a/build-docs.sh b/build-docs.sh index 67c3cdc..36d8a71 100755 --- a/build-docs.sh +++ b/build-docs.sh @@ -2,7 +2,10 @@ set -euo pipefail -rm -rf docs/build .jupyter_cache +rm -rf docs/source/tutorials docs/source/sg_execution_times.rst +rm -rf docs/build +rm -rf .jupyter_cache + mkdir -p docs/source/_static sphinx-build -E -a -b html docs/source docs/build/html diff --git a/docs-requirements.txt b/docs-requirements.txt deleted file mode 100644 index 1f9e5bb..0000000 --- a/docs-requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -sphinx~= 8.1 -pydata-sphinx-theme -sphinx_copybutton -myst_nb -myst-parser -sphinx_design -sphinx-gallery \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..7c24842 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +pyaml-test-lattice==0.1.0a2 +git+https://github.com/python-accelerator-middle-layer/pyaml.git@main +pyaml-cs-oa[tango] @ git+https://github.com/python-accelerator-middle-layer/pyaml-cs-oa.git@main \ No newline at end of file diff --git a/docs/source/_static/create_accelerator.png b/docs/source/_static/create_accelerator.png new file mode 100644 index 0000000..4bf9e1b Binary files /dev/null and b/docs/source/_static/create_accelerator.png differ diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css index 3e7ff8d..7e1083f 100644 --- a/docs/source/_static/custom.css +++ b/docs/source/_static/custom.css @@ -11,3 +11,31 @@ a.gh-link:visited { .sphx-glr-download-zip { display: none; } + +/* Change the number of columns in the sphinx gallery grid */ +/* .sphx-glr-thumbnails { + grid-template-columns: 1fr; + gap: 1rem; +} */ + +.sphx-glr-signature { + display: none; +} + +/* Modifications to show the output as in a notebook */ +.sphx-glr-script-out::before { + display: none !important; + content: none !important; +} + +.sphx-glr-script-out, +.sphx-glr-script-out div.highlight, +.sphx-glr-script-out pre { + background: transparent !important; + border: none !important; + box-shadow: none !important; +} + +.sphx-glr-script-out pre { + padding: 0; +} diff --git a/docs/source/_static/inspect_accelerator.png b/docs/source/_static/inspect_accelerator.png new file mode 100644 index 0000000..5e2df78 Binary files /dev/null and b/docs/source/_static/inspect_accelerator.png differ diff --git a/docs/source/conf.py b/docs/source/conf.py index 1e8aaf9..95302fc 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,3 +1,5 @@ +from sphinx_gallery.sorting import FileNameSortKey + # Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: @@ -31,8 +33,13 @@ ] sphinx_gallery_conf = { - "examples_dirs": "tutorials_src", - "gallery_dirs": "tutorials", + "examples_dirs": ["../tutorials"], + "gallery_dirs": ["tutorials"], + "filename_pattern": r"\.py$", + "show_memory": False, + "remove_config_comments": True, + "min_reported_time": 999999, + "within_subsection_order": FileNameSortKey("../tutorials"), # Binder (cloud notebook) "binder": { @@ -40,17 +47,16 @@ "repo": "documentation", "branch": "main", "binderhub_url": "https://mybinder.org", - "dependencies": ["../../requirements.txt"], + "dependencies": ["../requirements.txt"], "use_jupyter_lab": True, }, } -exclude_patterns += [ - "tutorials/*.ipynb", +exclude_patterns = [ "tutorials/*.py", + "tutorials/*.ipynb", "tutorials/*.zip", "tutorials/*.codeobj.json", - "tutorials_src/GALLERY_HEADER.rst" ] # -- Options for HTML output ------------------------------------------------- @@ -67,4 +73,6 @@ } html_theme_options = { "secondary_sidebar_items": ["page-toc","sg_download_links", "sg_launcher_links"], + "pygments_light_style": "default", + "pygments_dark_style": "monokai", } diff --git a/docs/source/tutorials_src/GALLERY_HEADER.rst b/docs/source/tutorials_src/GALLERY_HEADER.rst deleted file mode 100644 index 331b3f6..0000000 --- a/docs/source/tutorials_src/GALLERY_HEADER.rst +++ /dev/null @@ -1,4 +0,0 @@ -Tutorials -========= - -Here you can find learning-oriented tutorials that guide you through the functionality of pyAML step by step. diff --git a/docs/source/tutorials_src/test_page.py b/docs/source/tutorials_src/test_page.py deleted file mode 100644 index 48e9d92..0000000 --- a/docs/source/tutorials_src/test_page.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Test page -================= - -This is a minimal Sphinx-Gallery example you can use to verify that: - -- the page is picked up by Sphinx-Gallery -- code cells are executed -- plots are rendered -- the Binder button appears on the generated page -""" - -# %% -# Imports -# ------- - -import numpy as np -import matplotlib.pyplot as plt - -# %% -# Create some data -# ---------------- - -x = np.linspace(0, 2 * np.pi, 200) -y = np.sin(x) - -# %% -# Plot the data -# ------------- - -fig, ax = plt.subplots(figsize=(6, 4)) -ax.plot(x, y, label="sin(x)") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.set_title("Sphinx-Gallery test plot") -ax.grid(True) -ax.legend() - -plt.show() - -# %% -# A second cell -# ------------- - -x2 = np.linspace(0, 2 * np.pi, 30) -y2 = np.cos(x2) - -fig, ax = plt.subplots(figsize=(6, 4)) -ax.scatter(x2, y2, label="cos(x)", marker="o") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.set_title("Second plot") -ax.grid(True) -ax.legend() - -plt.show() \ No newline at end of file diff --git a/docs/tutorials/01_create_accelerator.py b/docs/tutorials/01_create_accelerator.py new file mode 100644 index 0000000..0717289 --- /dev/null +++ b/docs/tutorials/01_create_accelerator.py @@ -0,0 +1,207 @@ +# --- +# jupyter: +# jupytext: +# cell_metadata_filter: -all +# custom_cell_magics: kql +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.11.2 +# kernelspec: +# display_name: pyaml-documentation +# language: python +# name: python3 +# --- + +# %% +""" +Create an Accelerator +========================================================== + +This tutorial shows the different ways to create a pyAML accelerator. + +The example only uses the simulator mode. The other modes are explored in other tutorials. + +The first approach constructs the objects interactively whereas the second one creates them +by loading a configuration file. Both produce the same final interface, but each is suited +to different use cases which will be explained in the tutorial. +""" + +# %% +# Prerequisites +# ------------- +# +# This tutorial requires a lattice file in a format supported by +# `pyAT `_. +# +# The example uses the lattice provided by the ``pyaml-test-lattice`` package. + +# Get the path to the lattice file +# sphinx_gallery_thumbnail_path = '_static/create_accelerator.png' +from pyaml_test_lattice import lattices + +# List available files and their descriptions +print(lattices) + +lattice_file = lattices['fodo_1gev_6d.json'] + +# %% +# Approach 1: Interactive Creation +# ------------------------------------ +# +# In the first approach the different parts of the accelerator is created interactively. +# In this example we will only create a single quadrupole magnet to use with the simulator mode. + +# %% +# Create a Quadrupole Magnet +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from pyaml.magnet.identity_model import IdentityMagnetModel +from pyaml.magnet.quadrupole import Quadrupole +from pyaml.lattice.simulator import Simulator + +# Create a model for the magnet +model = IdentityMagnetModel(physics='') + +# Create the quadrupole +quad = Quadrupole(name="QF_001", model=model) + +# Create the simulator +simulator = Simulator(name="design", lattice=lattice_file) + +# Attach the quadrupole to the simulator +simulator.fill_device([quad]) +quad = simulator.magnet.get("QF_001") + +# %% +# Read and Set the Quadrupole Strength +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +print(f"Initial strength: {quad.strength.get()}") + +quad.strength.set(0.504) + +print(f"Updated strength: {quad.strength.get()}") + +# %% +# Create an Accelerator +# ~~~~~~~~~~~~~~~~~~~~~ +# You can also create an accelerator. +# +# This is not strictly necessary for this simple example with only a single device. +# However, it provides an interface for adding metadata, +# supporting multiple control modes, and grouping devices. +# +# The features of the accelerator is explored in other tutorials. + +from pyaml.accelerator import Accelerator + +simulator._MAGNETS.pop("QF_001", None) +simulator._ALL.pop("QF_001", None) + +accelerator = Accelerator( + facility="pyAML_test_facility", + machine="pyaml_test_machine", + energy=1e9, + simulators=[simulator], + devices=[quad] +) + +# Get the quadrupole +quad = accelerator.design.magnet.get("QF_001") + +# Read the strength in the same way as before +quad.strength.get() + + +# %% +# Approach 2: Load a Configuration +# ------------------------------------- +# Devices can also be created by loading a configuration file. +# +# Configuration files are loaded through the interface of the accelerator and +# are intended to be used for use cases with many devices, several control modes etc. +# +# Configuration files can be written in YAML or JSON. This example shows a YAML file. + + +# %% +# Create a YAML file +# ~~~~~~~~~~~~~~~~~~ +# The YAML file can be created using different tools. More details can be found in the the how-to guides. +# In this example we create it directly here. + +import yaml + +data = { + "type": "pyaml.accelerator", + "facility": "pyAML test facility", + "machine": "pyaml test machine", + "data_folder": None, + "energy": None, + "simulators": [ + { + "type": "pyaml.lattice.simulator", + "lattice": "${env:PYAML_TEST_LATTICE}", + "name": "design", + } + ], + "devices": [ + { + "type": "pyaml.magnet.quadrupole", + "name": "QF_001", + "model": { + "type": "pyaml.magnet.identity_model", + "physics": "", + }, + } + ], +} + +with open("config.yaml", "w", encoding="utf-8") as file: + yaml.safe_dump(data, file, sort_keys=False) + +# %% +# Specify the Path to the Configuration File +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# The path to the configuration file can be specified as absolute or relative to a root directory. + +# Set the root directory +from pathlib import Path +from pyaml.configuration import ROOT + +current_dir = Path.cwd() +ROOT.set(current_dir) + +# Display the loaded content +config_path = Path('config.yaml') +print(config_path.read_text()) + + +# %% +# Specify the Path to the Lattice File +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# The path to the lattice file can be specified in the configuration file +# as absolute or relative to the root directory. +# +# It is also possible to specify it using an environment variable. +# The syntax for that is shown in this example. + +import os +os.environ["PYAML_TEST_LATTICE"] = lattice_file + +# %% +# Create an Accelerator +# ~~~~~~~~~~~~~~~~~~~~~ +from pyaml.accelerator import Accelerator + +accelerator = Accelerator.load('config.yaml') + +# Get the quadrupole +quad = accelerator.design.magnet.get('QF_001') + +# Use the quadrupole in the same way as before +quad.strength.get() + +# %% diff --git a/docs/tutorials/02_inspect_accelerator.py b/docs/tutorials/02_inspect_accelerator.py new file mode 100644 index 0000000..2fb9062 --- /dev/null +++ b/docs/tutorials/02_inspect_accelerator.py @@ -0,0 +1,44 @@ +# %% +""" +Inspect an Accelerator +========================================================== + +This tutorial shows how to inspect and access the content of the accelerator. +""" + +# %% +# Prerequisites +# ------------- +# +# This tutorial requires an existing pyAML configuration file. +# +# The example uses the configuration provided by the ``pyaml-test-lattice`` package. + +# Get the path to the configuration file +# sphinx_gallery_thumbnail_path = '_static/inspect_accelerator.png' +from pyaml_test_lattice import configurations + +# List available files and their descriptions +configurations + +# %% +# Load the Accelerator +# -------------------- + +from pyaml.accelerator import Accelerator +accelerator = Accelerator.load(configurations["pyaml/tango/pyaml-cs-oa/fodo_1gev_6d_pyaml-oa.yaml"]) + +# %% +# Inspect the Accelerator Contents +# ------------------------------------ +# +# The yellow pages provide an overview of the accelerator. +# This shows what is configured and available for use. + +accelerator.yellow_pages + +# %% +# Show the Configuration of a Magnet +# ------------------------------------ + +accelerator.design.magnets.get("QF_001") diff --git a/docs/tutorials/GALLERY_HEADER.rst b/docs/tutorials/GALLERY_HEADER.rst new file mode 100644 index 0000000..919cc16 --- /dev/null +++ b/docs/tutorials/GALLERY_HEADER.rst @@ -0,0 +1,7 @@ +Tutorials +========= + +Here you can find learning-oriented tutorials that guide you through the functionality of pyAML step by step. + +The tutorials are designed to be followed in sequence, gradually increasing in complexity but +each tutorial is self-contained and can also be completed independently. diff --git a/requirements.txt b/requirements.txt index 515baaf..9021b3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,8 @@ -numpy -matplotlib -pyaml \ No newline at end of file +sphinx~= 8.1 +pydata-sphinx-theme +sphinx_copybutton +myst_nb +myst-parser +sphinx_design +sphinx-gallery +jupytext \ No newline at end of file