diff --git a/.github/workflows/compilation.yml b/.github/workflows/compilation.yml
index c06d3621..c40130af 100644
--- a/.github/workflows/compilation.yml
+++ b/.github/workflows/compilation.yml
@@ -34,8 +34,8 @@ jobs:
- name: Print Versions
run: |
- .github/workflows/pip-versions.sh
-
+ .github/workflows/pip-versions.sh
+
centos-stream:
runs-on: ubuntu-latest
@@ -60,8 +60,8 @@ jobs:
- name: Print Versions
run: |
- .github/workflows/pip-versions.sh
-
+ .github/workflows/pip-versions.sh
+
ubuntu:
@@ -88,7 +88,7 @@ jobs:
- name: Print Versions
run: |
- .github/workflows/pip-versions.sh
+ .github/workflows/pip-versions.sh
conda:
@@ -120,7 +120,7 @@ jobs:
- name: Print Versions
run: |
- .github/workflows/conda-versions.sh
+ .github/workflows/conda-versions.sh
mpich:
runs-on: ubuntu-latest
@@ -145,4 +145,7 @@ jobs:
- name: Print Versions
run: |
- .github/workflows/pip-versions.sh
\ No newline at end of file
+ .github/workflows/pip-versions.sh
+
+ build-docs:
+ uses: ./.github/workflows/docs-build.yml
diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml
new file mode 100644
index 00000000..85f4143a
--- /dev/null
+++ b/.github/workflows/docs-build.yml
@@ -0,0 +1,42 @@
+on:
+ workflow_call:
+ inputs:
+ upload-artifact:
+ required: false
+ type: boolean
+ default: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Miniconda
+ uses: conda-incubator/setup-miniconda@v3
+ with:
+ activate-environment: po3
+ channels: conda-forge,defaults
+ auto-update-conda: true
+ environment-file: ./doc/environment.yml
+
+ - name: Install PyORBIT3
+ shell: bash -l {0}
+ run: |
+ # @woodtp -- MPI isn't required to build docs and enabling it causes Sphinx to segfault.
+ conda activate po3
+ pip install --config-settings=setup-args="-DUSE_MPI='none'" .
+
+ - name: Build Documentation
+ shell: bash -l {0}
+ run: |
+ conda activate po3
+ cd doc
+ make dirhtml
+
+ - name: Upload artifact
+ if: ${{ inputs.upload-artifact }}
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: './doc/build/dirhtml'
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index ce5f24dc..f7b27d12 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -1,15 +1,11 @@
-# Simple workflow for deploying static content to GitHub Pages
name: Deploy Documentation to Pages
on:
- # Runs on pushes targeting the default branch
push:
branches: ["main"]
- # Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
-# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
@@ -22,29 +18,36 @@ concurrency:
cancel-in-progress: false
jobs:
- # Single deploy job since we're just deploying
+ build:
+ uses: ./.github/workflows/docs-build.yml
+ with:
+ upload-artifact: true
+
deploy:
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
+ needs: build
runs-on: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v4
- - uses: conda-incubator/setup-miniconda@v2
- with:
- activate-environment: po3
- environment-file: docs-environment.yml
- - uses: ammaraskar/sphinx-action@master
- with:
- docs-folder: "doc/"
- # - name: Setup Pages
- # uses: actions/configure-pages@v5
- - name: Upload artifact
- uses: actions/upload-pages-artifact@v3
- with:
- # Upload entire repository
- path: './doc/build/html'
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@v4
+ - name: Download Artifact
+ uses: actions/download-artifact@v5
+ with:
+ name: github-pages
+ - name: Extract artifact.tar in place
+ run: |
+ TARFILE=$(find . -type f -name "*.tar*" | head -n1)
+ if [ -z "$TARFILE" ]; then
+ echo "No tar archive found in workspace"
+ ls -la
+ exit 1
+ fi
+ mkdir -p ./site
+ tar -xvf "$TARFILE" -C ./site
+
+ - name: List extracted site
+ run: ls -R ./site
+
+ - name: Deploy
+ uses: peaceiris/actions-gh-pages@v4
+ with:
+ deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
+ external_repository: pyorbit-collaboration/pyorbit-collaboration.github.io
+ publish_dir: ./site
diff --git a/.gitignore b/.gitignore
index 47650c0e..da0ba329 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,9 @@ PyORBIT.egg-info
*.so
.*.swp
.eggs
+.venv
+_autosummary/
+_api/
+_cpp_api/
+doc/source/reference/*.rst
+doc/source/reference/*.rst.include
diff --git a/README.md b/README.md
index 8e5b4277..b896f29f 100644
--- a/README.md
+++ b/README.md
@@ -29,16 +29,16 @@ The following commands may require root access.
Click for Ubuntu-based distributions
-
+
```bash
apt-get update
apt-get install -y build-essential python3 libfftw3-dev python3-venv libpython3-dev pkg-config git
- ```
+ ```
Click for Redhat-based distributions
-
+
```bash
dnf group install -y "Development Tools"
dnf install -y python3-devel fftw3-devel
@@ -47,16 +47,18 @@ The following commands may require root access.
Click for Mac
-
+
Install Homebrew, make sure that homebrew programs are in the **$PATH** (optional step in Homebrew installation)
+
```bash
brew install pkg-config fftw
```
-
+
#### Create Python virtual environment
Make sure that you have the correct python version installed. We require python>3.9.
Create virtual environment.
+
```
python3 -m venv .po3
. .po3/bin/activate
@@ -70,6 +72,7 @@ The following commands may require root access.
First of all make sure you have conda installed and development packages.
Development packages for Ubuntu:
+
```
apt update -y
apt install -y curl gpg git build-essential
@@ -87,18 +90,18 @@ pip install -U meson-python setuptools setuptools-scm
## 3. Build
-If you plan to modify PyORBIT's code, install it in editable mode.
+If you plan to modify PyORBIT's code, install it in editable mode.
You will NOT need to rebuild after modifications to the code. [Meson](MesonBuild.md) will rebuild as necessary on import.
```
pip install --no-build-isolation --editable .
```
Alternatively if you don't plan to modify PyORBIT's code
+
```
pip install .
```
-
## 4. Run full SNS linac example
Navigate to your **examples** directory and launch tracking of SNS linac.
@@ -116,9 +119,9 @@ pip install --config-settings=setup-args="-DUSE_MPI=none" .
Above will build PyORBIT without MPI even if MPI is present. You can change that option to `mpich`, `ompi`, `none` or `auto` (default).
| MPI flavor | Installation command |
|---------------|--------------|
-| No MPI | `pip install --config-settings=setup-args="-DUSE_MPI=none" .` |
-| The first found MPI installation if any | `pip install --config-settings=setup-args="-DUSE_MPI=auto" .` |
-| OpenMPI | `pip install --config-settings=setup-args="-DUSE_MPI=ompi" .` |
+| No MPI | `pip install --config-settings=setup-args="-DUSE_MPI=none" .` |
+| The first found MPI installation if any | `pip install --config-settings=setup-args="-DUSE_MPI=auto" .` |
+| OpenMPI | `pip install --config-settings=setup-args="-DUSE_MPI=ompi" .` |
| MPICH | `pip install --config-settings=setup-args="-DUSE_MPI=mpich" .` |
Meson uses PKG_CONFIG to discover packages. It could be useful to help it to find your MPI installation:
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 00000000..ca5796cb
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,2 @@
+_doxygen
+source/api
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 00000000..3767ad00
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,24 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile clean
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+clean:
+ rm -rf "$(SOURCEDIR)"/_doxygen "$(SOURCEDIR)"/reference/*.rst{,.include} "$(SOURCEDIR)"/_autosummary
+ @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/environment.yml b/doc/environment.yml
new file mode 100644
index 00000000..c7a2e01f
--- /dev/null
+++ b/doc/environment.yml
@@ -0,0 +1,23 @@
+name: docs
+channels:
+ - conda-forge
+dependencies:
+ - doxygen
+ - exhale
+ - pydata-sphinx-theme
+ - python=3.13
+ - sphinx
+ - sphinx-copybutton
+ - sphinx-autodoc-typehints
+ - sphinx-automodapi
+ - myst-parser
+ - breathe
+ - standard-imghdr
+ - fftw
+ - numpy
+ - scipy
+ - matplotlib
+ - meson
+ - pkg-config
+ - ninja
+ - graphviz
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644
index 00000000..747ffb7b
--- /dev/null
+++ b/doc/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/doc/placeholder b/doc/source/_static/.gitkeep
similarity index 100%
rename from doc/placeholder
rename to doc/source/_static/.gitkeep
diff --git a/doc/source/_templates/.gitkeep b/doc/source/_templates/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 00000000..b9496fef
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,87 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+import sys
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).parent.parent / "py/"))
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = "PyORBIT3"
+copyright = "2025, PyORBIT Collaboration"
+author = "PyORBIT Collaboration"
+release = "v3.0.1"
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = [
+ "sphinx.ext.coverage",
+ "sphinx.ext.todo",
+ "sphinx.ext.viewcode",
+ # "sphinx.ext.autodoc",
+ # "sphinx.ext.autosummary",
+ "sphinx.ext.napoleon",
+ "sphinx_autodoc_typehints",
+ "sphinx_automodapi.automodapi",
+ "sphinx_automodapi.smart_resolver",
+ "sphinx_copybutton",
+ "myst_parser",
+ "breathe",
+ "exhale",
+]
+
+autodoc_typehints = "description"
+
+napoleon_numpy_docstring = True
+autosummary_imported_members = True
+
+numpydoc_show_class_members = False
+automodapi_toctreedirnm = "reference"
+
+templates_path = ["_templates"]
+exclude_patterns = []
+
+# -- Breathe and Exhale Options ---------------------------------------------------------
+breathe_projects = {
+ "PyORBIT3": "./_doxygen/xml",
+}
+breathe_default_project = "PyORBIT3"
+
+doxyfile = "\n".join(
+ [
+ "INPUT = ../../src",
+ "EXCLUDE_PATTERNS = *wrap* *_init.cc",
+ "PREDEFINED += DOXYGEN_SHOULD_SKIP_THIS",
+ 'PREDEFINED += PyObject_HEAD="PyObject ob_base;"',
+ ]
+)
+
+exhale_args = {
+ "containmentFolder": "./reference",
+ "rootFileName": "cpp.rst",
+ "doxygenStripFromPath": "..",
+ "rootFileTitle": "C++ API Reference",
+ "fullApiSubSectionTitle": "",
+ "createTreeView": True,
+ "exhaleExecutesDoxygen": True,
+ "exhaleDoxygenStdin": doxyfile,
+}
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = "pydata_sphinx_theme"
+html_static_path = ["_static"]
+html_show_source_link = True
+html_theme_options = {
+ "github_url": "https://github.com/PyORBIT-Collaboration/PyORBIT3",
+ "logo": {
+ "text": "PyORBIT3",
+ },
+}
diff --git a/doc/source/contributing.md b/doc/source/contributing.md
new file mode 100644
index 00000000..110f6fdb
--- /dev/null
+++ b/doc/source/contributing.md
@@ -0,0 +1,146 @@
+# Contributor Guide
+
+## Building the Docs
+
+To build and preview the documentation locally, create a new Conda environment from the `docs-environment.yml` and activate it.
+Then, `cd` into the `doc/` directory and run `make html`.
+
+```sh
+conda env create -f docs-environment.yml -n docs
+conda activate docs
+cd doc
+make html
+```
+
+You can view the documentation in your browser by opening `docs/build/html/index.html`.
+
+## Creating Static Pages
+
+Simple pages may be written in Markdown or [reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) and stored in the `doc/source/` directory.
+Markdown support is enabled via the MyST parser extension, refer to the [MyST syntax guide](https://myst-parser.readthedocs.io/en/latest/syntax/typography.html)
+for more information related to composition of Markdown documents.
+Add the file to a `toc` block in the `doc/source/index.rst` in order for it be included in the main documentation.
+
+
+1. Create your document containing useful information under `doc/source/useful_info.md`.
+
+```md
+
+
+# Useful Information
+```
+
+2. Add the file to a `toc` block in the `doc/source/index.rst`.
+
+```rst
+.. toctree::
+
+ useful_info
+```
+
+:::{tip}
+If you want to create a hierarchical structure of pages, add the subdirectory to the `doc/source/` directory and add the file to a `toc` block in the parent file.
+:::
+
+## Documenting Python Code
+
+### Where to add documentation
+
+Add or edit docstrings directly in the Python source files following the NumPy docstring style.
+For generated API pages, autosummary will produce stub pages from the docstrings and signatures.
+Any new top-level `orbit` submodule must be registered by adding it to `docs/source/modules.rst`.
+
+### Docstring format
+
+Use the [NumPy docstring convention](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard).
+Keep short summary on the first line.
+Use Parameters with a table-like list; include types and optional default values.
+
+```python
+def foo(x, y=1):
+ """
+ Short one-line summary.
+
+ Longer description (optional), explaining behavior, side effects, and important details.
+
+ .. math::
+
+ z = x \cdot y
+
+ Parameters
+ ----------
+ x : int
+ Description of x.
+ y : int, optional
+ Description of y. Defaults to 1.
+
+ Returns
+ -------
+ float
+ Description of the return value.
+
+ Raises
+ ------
+ ValueError
+ If x is negative.
+
+ """
+ ...
+```
+
+## Documenting C++ Code
+
+### Where to add documentation
+
+Add Doxygen comments directly in the C++ header or source files above the declarations.
+
+Example documenting a function:
+
+```cpp
+/**
+ * @brief Compute a simple value.
+ *
+ * The relation is given by the LaTeX expression: \f\$ z = x \cdot y \f\$.
+ * Detailed description if needed.
+ *
+ * @param x First input.
+ * @param y Second input.
+ * @return Computed value.
+ * @throws std::invalid\_argument if x <= 0.
+ *
+ * Example:
+ * @code
+ * double r = foo(x, y);
+ * @endcode
+ */
+double foo(double x, double y);
+```
+
+Example documenting a class:
+
+```cpp
+/**
+ * @class Bar
+ * @brief Represents a simple concept.
+ *
+ * More detailed class description.
+ *
+ * Mathematical note: \f\$E = mc^2\f\$
+ */
+class Bar {
+public:
+ /** Construct with a value. */
+ Bar(double v);
+ /** Return the value. */
+ double value() const;
+ // ...
+};
+```
+
+## For Maintainers
+
+The docs are deployed to the [main GitHub Pages repository for the PyORBIT Collaboration](https://github.com/pyorbit-collaboration/pyorbit-collaboration.github.io)
+via an Action ([peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages)) defined in [PyORBIT-Collaboration/PyORBIT3/.github/workflow/docs.yml](https://github.com/PyORBIT-Collaboration/PyORBIT3/blob/main/.github/workflows/docs.yml).
+The action requires a [Deploy Key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys) to be added to the PyORBIT-Collaboration/PyORBIT-Collaboration.github.io repository
+as well as a [Secret](https://docs.github.com/en/actions/security-guides/automatic-token-authentication) to be created in the PyORBIT-Collaboration/PyORBIT3 repository.
+Refer to the [instructions for deploying to an external repository](https://github.com/peaceiris/actions-gh-pages?tab=readme-ov-file#%EF%B8%8F-deploy-to-external-repository-external_repository) and [Create SSH Deploy Key](https://github.com/peaceiris/actions-gh-pages?tab=readme-ov-file#tips-and-faq) for more details.
diff --git a/doc/source/home.md b/doc/source/home.md
new file mode 100644
index 00000000..11a94892
--- /dev/null
+++ b/doc/source/home.md
@@ -0,0 +1 @@
+# PyORBIT3
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 00000000..55503272
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1,28 @@
+.. PyORBIT3 documentation master file, created by
+ sphinx-quickstart on Mon Dec 15 20:07:23 2025.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+.. include:: ./home.md
+ :parser: myst_parser.sphinx_
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Getting Started
+
+ install
+ contributing
+
+.. toctree::
+ :maxdepth: 2
+ :caption: API Reference
+
+ reference/py
+ reference/cpp
+
+
+Indices and tables
+==================
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/doc/source/install.md b/doc/source/install.md
new file mode 100644
index 00000000..db05c1d2
--- /dev/null
+++ b/doc/source/install.md
@@ -0,0 +1,211 @@
+# Installation Guide
+
+```{contents}
+:depth: 3
+```
+
+This guide provides instructions how to install PyORBIT code.
+This guide doesn't cover MPI enabled installation.
+The following configurations are included in CI testing, versions will change as the runner images progress.
+
+| HW | Architecture | OS | Python | Compiler | Package |
+|---------------|--------------|---------------|---------|--------------|--------------|
+| PC | x86_64 | CentOS latest | 3.9.18 | gcc-11.4.1 | pip-24.0 |
+| PC | x86_64 | Ubuntu latest | 3.12.3 | gcc-13.2.0 | pip-24.0 |
+| Apple Silicon | arm64 | macOS 14 | 3.12.3 | clang-15.0.0 | pip-24.0 |
+| PC | x86_64 | Ubuntu latest | 3.10.14 | gcc-13.2.0 | conda-24.5.0 |
+
+
+
+## Installation from source
+
+First step is to clone the source code:
+
+```bash
+git clone https://github.com/PyORBIT-Collaboration/PyORBIT3.git
+```
+
+### Pip Setup
+**PIP** based setup is more involved, we recommend using **conda** if unsure.
+#### Prepare OS
+The following commands may require root access.
+
+
+ Click for Ubuntu-based distributions
+
+ ```bash
+ apt-get update
+ apt-get install -y build-essential python3 libfftw3-dev python3-venv libpython3-dev pkg-config git
+ ```
+
+
+
+ Click for Redhat-based distributions
+
+ ```bash
+ dnf group install -y "Development Tools"
+ dnf install -y python3-devel fftw3-devel
+ ```
+
+
+
+ Click for Mac
+
+ Install Homebrew, make sure that homebrew programs are in the **$PATH** (optional step in Homebrew installation)
+
+ ```bash
+ brew install pkg-config fftw
+ ```
+
+
+ #### Create Python virtual environment
+ Make sure that you have the correct python version installed. We require python>3.9.
+ Create virtual environment.
+
+ ```
+ python3 -m venv .po3
+ . .po3/bin/activate
+ pip install -U pip
+ pip install -r requirements.txt
+ pip install -U setuptools
+ ```
+
+
+### Conda Setup
+
+First of all make sure you have conda installed and development packages.
+Development packages for Ubuntu:
+
+```
+apt update -y
+apt install -y curl gpg git build-essential
+```
+
+Then run the following:
+
+```bash
+cd pyorbit3
+conda env create -n po3 --file environment.yml
+conda activate po3
+pip install -U meson-python setuptools setuptools-scm
+```
+
+
+## Build
+
+If you plan to modify PyORBIT's code, install it in editable mode.
+You will NOT need to rebuild after modifications to the code. [Meson](meson-primer) will rebuild as necessary on import.
+```
+pip install --no-build-isolation --editable .
+```
+
+Alternatively if you don't plan to modify PyORBIT's code
+
+```
+pip install .
+```
+
+## 4. Run full SNS linac example
+
+Navigate to your **examples** directory and launch tracking of SNS linac.
+
+```bash
+cd examples/SNS_Linac/pyorbit3_linac_model/
+python pyorbit3_sns_linac_mebt_hebt2.py
+```
+
+## MPI consideration
+
+By default, the build system will try to find MPI and compile against it. You can control which MPI to use with command line option when building.
+```bash
+pip install --config-settings=setup-args="-DUSE_MPI=none" .
+```
+Above will build PyORBIT without MPI even if MPI is present. You can change that option to `mpich`, `ompi`, `none` or `auto` (default).
+| MPI flavor | Installation command |
+|---------------|--------------|
+| No MPI | `pip install --config-settings=setup-args="-DUSE_MPI=none" .` |
+| The first found MPI installation if any | `pip install --config-settings=setup-args="-DUSE_MPI=auto" .` |
+| OpenMPI | `pip install --config-settings=setup-args="-DUSE_MPI=ompi" .` |
+| MPICH | `pip install --config-settings=setup-args="-DUSE_MPI=mpich" .` |
+
+Meson uses PKG_CONFIG to discover packages. It could be useful to help it to find your MPI installation:
+
+```bash
+PKG_CONFIG_PATH=/opt/lib/pkgconfig pip install --verbose .
+```
+
+(meson-primer)=
+# Meson Primer
+
+This uses meson-python to build orbit package.
+
+There is no **setup.py** file, instead we have **meson.build**.
+**pyproject.toml** is changed to use meson.
+
+This is experimental setup that is work in progress.
+The pure python part is built with hierarchical **meson.build** files in **py/**.
+The C++ setup is combined in one file **src/meson.build**.
+
+## Main modifications in C++ code
+1. **src/libmain/** is not used, still there for reference but will be gone soon.
+2. **src/core/** contains one C++ file per module inside _orbit.core_
+3. The files **wrap_XXXX.cc** were modified to correctly reference modules
+```cpp
+// line
+PyObject* mod = PyImport_ImportModule("_bunch");
+// replaced with
+PyObject* mod = PyImport_ImportModule("orbit.core.bunch");
+```
+
+## Setup
+
+### 0. Required software
+
+One needs compilers, python and libfftw (and potentially mpi).
+See [PyORBIT3](https://github.com/PyORBIT-Collaboration/PyORBIT3) for external
+requirements.
+
+
+### 1. Preparing environment
+
+First step is to clone the source code from meson branch:
+
+```bash
+git clone -b meson https://github.com/azukov/PyORBIT3.git
+```
+
+Initialize new virtual environment and install packages
+
+```
+python -m venv .mes
+source .mes/bin/activate
+pip install -U pip
+pip install -r requirements
+```
+Edit **meson.build** and set correct paths/flags for python/fftw3 headers and libraries
+
+## 2. Build
+
+To install orbit package in development mode run following:
+```bash
+ pip install --no-build-isolation --editable .
+```
+No rebuild is necessary, just edit **py/** or **src/** and meson will rebuild as needed when import happens.
+
+
+### 3. Run examples
+
+Special examples used for meson testing
+
+```bash
+cd examples/meson
+python imports_test.py
+python uspas_test.py
+```
+
+SNS linac example
+```bash
+cd examples/SNS_Linac/pyorbit3_linac_model/
+python pyorbit3_sns_linac_mebt_hebt2.py
+```
+
diff --git a/doc/source/reference/orbit.aperture.md b/doc/source/reference/orbit.aperture.md
new file mode 100644
index 00000000..7cdfeb25
--- /dev/null
+++ b/doc/source/reference/orbit.aperture.md
@@ -0,0 +1,6 @@
+# orbit.aperture
+
+```{eval-rst}
+.. automodapi:: orbit.aperture
+ :no-heading:
+```
diff --git a/doc/source/reference/orbit.bumps.md b/doc/source/reference/orbit.bumps.md
new file mode 100644
index 00000000..9843c369
--- /dev/null
+++ b/doc/source/reference/orbit.bumps.md
@@ -0,0 +1,6 @@
+# orbit.bumps
+
+```{eval-rst}
+.. automodapi:: orbit.bumps
+ :no-heading:
+```
diff --git a/doc/source/reference/orbit.bunch_generators.md b/doc/source/reference/orbit.bunch_generators.md
new file mode 100644
index 00000000..3cd509c1
--- /dev/null
+++ b/doc/source/reference/orbit.bunch_generators.md
@@ -0,0 +1,6 @@
+# orbit.bunch_generators
+
+```{eval-rst}
+.. automodapi:: orbit.bunch_generators
+ :no-heading:
+```
diff --git a/doc/source/reference/orbit.bunch_utils.md b/doc/source/reference/orbit.bunch_utils.md
new file mode 100644
index 00000000..a13530fb
--- /dev/null
+++ b/doc/source/reference/orbit.bunch_utils.md
@@ -0,0 +1,6 @@
+# orbit.bunch_utils
+
+```{eval-rst}
+.. automodapi:: orbit.bunch_utils
+ :no-heading:
+```
diff --git a/doc/source/reference/orbit.collimation.md b/doc/source/reference/orbit.collimation.md
new file mode 100644
index 00000000..49e5aa3f
--- /dev/null
+++ b/doc/source/reference/orbit.collimation.md
@@ -0,0 +1,6 @@
+# orbit.collimation
+
+```{eval-rst}
+.. automodapi:: orbit.collimation
+ :no-heading:
+```
diff --git a/doc/source/reference/orbit.core.md b/doc/source/reference/orbit.core.md
new file mode 100644
index 00000000..6cc6c69b
--- /dev/null
+++ b/doc/source/reference/orbit.core.md
@@ -0,0 +1,6 @@
+# orbit.core
+
+```{eval-rst}
+.. automodapi:: orbit.core
+ :no-heading:
+```
diff --git a/doc/source/reference/orbit.diagnostics.md b/doc/source/reference/orbit.diagnostics.md
new file mode 100644
index 00000000..5de6a8d6
--- /dev/null
+++ b/doc/source/reference/orbit.diagnostics.md
@@ -0,0 +1,6 @@
+# orbit.diagnostics
+
+```{eval-rst}
+.. automodapi:: orbit.diagnostics
+ :no-heading:
+```
diff --git a/doc/source/reference/orbit.errors.md b/doc/source/reference/orbit.errors.md
new file mode 100644
index 00000000..aa2e69ef
--- /dev/null
+++ b/doc/source/reference/orbit.errors.md
@@ -0,0 +1,7 @@
+# orbit.errors
+
+```{eval-rst}
+.. automodapi:: orbit.errors
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.fieldtracker.md b/doc/source/reference/orbit.fieldtracker.md
new file mode 100644
index 00000000..b6e3bcdc
--- /dev/null
+++ b/doc/source/reference/orbit.fieldtracker.md
@@ -0,0 +1,7 @@
+# orbit.fieldtracker
+
+```{eval-rst}
+.. automodapi:: orbit.fieldtracker
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.foils.md b/doc/source/reference/orbit.foils.md
new file mode 100644
index 00000000..184c14f9
--- /dev/null
+++ b/doc/source/reference/orbit.foils.md
@@ -0,0 +1,7 @@
+# orbit.foils
+
+```{eval-rst}
+.. automodapi:: orbit.foils
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.impedances.md b/doc/source/reference/orbit.impedances.md
new file mode 100644
index 00000000..570b8b1f
--- /dev/null
+++ b/doc/source/reference/orbit.impedances.md
@@ -0,0 +1,7 @@
+# orbit.impedances
+
+```{eval-rst}
+.. automodapi:: orbit.impedances
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.injection.md b/doc/source/reference/orbit.injection.md
new file mode 100644
index 00000000..408659bb
--- /dev/null
+++ b/doc/source/reference/orbit.injection.md
@@ -0,0 +1,7 @@
+# orbit.injection
+
+```{eval-rst}
+.. automodapi:: orbit.injection
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.kickernodes.md b/doc/source/reference/orbit.kickernodes.md
new file mode 100644
index 00000000..a4754587
--- /dev/null
+++ b/doc/source/reference/orbit.kickernodes.md
@@ -0,0 +1,7 @@
+# orbit.kickernodes
+
+```{eval-rst}
+.. automodapi:: orbit.kickernodes
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.lattice.md b/doc/source/reference/orbit.lattice.md
new file mode 100644
index 00000000..9964c15a
--- /dev/null
+++ b/doc/source/reference/orbit.lattice.md
@@ -0,0 +1,7 @@
+# orbit.lattice
+
+```{eval-rst}
+.. automodapi:: orbit.lattice
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.matching.md b/doc/source/reference/orbit.matching.md
new file mode 100644
index 00000000..f62e1f87
--- /dev/null
+++ b/doc/source/reference/orbit.matching.md
@@ -0,0 +1,7 @@
+# orbit.matching
+
+```{eval-rst}
+.. automodapi:: orbit.matching
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.matrix_lattice.md b/doc/source/reference/orbit.matrix_lattice.md
new file mode 100644
index 00000000..c8e70bcb
--- /dev/null
+++ b/doc/source/reference/orbit.matrix_lattice.md
@@ -0,0 +1,7 @@
+# orbit.matrix_lattice
+
+```{eval-rst}
+.. automodapi:: orbit.matrix_lattice
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.orbit_correction.md b/doc/source/reference/orbit.orbit_correction.md
new file mode 100644
index 00000000..0ddec622
--- /dev/null
+++ b/doc/source/reference/orbit.orbit_correction.md
@@ -0,0 +1,7 @@
+# orbit.orbit_correction
+
+```{eval-rst}
+.. automodapi:: orbit.orbit_correction
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.parsers.md b/doc/source/reference/orbit.parsers.md
new file mode 100644
index 00000000..ce8b06c0
--- /dev/null
+++ b/doc/source/reference/orbit.parsers.md
@@ -0,0 +1,7 @@
+# orbit.parsers
+
+```{eval-rst}
+.. automodapi:: orbit.parsers
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.py_linac.md b/doc/source/reference/orbit.py_linac.md
new file mode 100644
index 00000000..5e00cfb2
--- /dev/null
+++ b/doc/source/reference/orbit.py_linac.md
@@ -0,0 +1,21 @@
+# orbit.py_linac
+
+```{eval-rst}
+.. automodapi:: orbit.py_linac.errors
+ :no-heading:
+.. automodapi:: orbit.py_linac.lattice
+ :no-heading:
+.. automodapi:: orbit.py_linac.lattice_modifications
+ :no-heading:
+.. automodapi:: orbit.py_linac.linac_parsers
+ :no-heading:
+.. automodapi:: orbit.py_linac.materials
+ :no-heading:
+.. automodapi:: orbit.py_linac.orbit_correction
+ :no-heading:
+.. automodapi:: orbit.py_linac.overlapping_fields
+ :no-heading:
+.. automodapi:: orbit.py_linac.rf_field_readers
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.rf_cavities.md b/doc/source/reference/orbit.rf_cavities.md
new file mode 100644
index 00000000..64bd5f4e
--- /dev/null
+++ b/doc/source/reference/orbit.rf_cavities.md
@@ -0,0 +1,7 @@
+# orbit.rf_cavities
+
+```{eval-rst}
+.. automodapi:: orbit.rf_cavities
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.space_charge.md b/doc/source/reference/orbit.space_charge.md
new file mode 100644
index 00000000..6d8c1049
--- /dev/null
+++ b/doc/source/reference/orbit.space_charge.md
@@ -0,0 +1,7 @@
+# orbit.space_charge
+
+```{eval-rst}
+.. automodapi:: orbit.space_charge
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.teapot.md b/doc/source/reference/orbit.teapot.md
new file mode 100644
index 00000000..ebe31a31
--- /dev/null
+++ b/doc/source/reference/orbit.teapot.md
@@ -0,0 +1,7 @@
+# orbit.teapot
+
+```{eval-rst}
+.. automodapi:: orbit.teapot
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.teapot_base.md b/doc/source/reference/orbit.teapot_base.md
new file mode 100644
index 00000000..b69030ad
--- /dev/null
+++ b/doc/source/reference/orbit.teapot_base.md
@@ -0,0 +1,7 @@
+# orbit.teapot_base
+
+```{eval-rst}
+.. automodapi:: orbit.teapot_base
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.time_dep.md b/doc/source/reference/orbit.time_dep.md
new file mode 100644
index 00000000..da5972eb
--- /dev/null
+++ b/doc/source/reference/orbit.time_dep.md
@@ -0,0 +1,7 @@
+# orbit.time_dep
+
+```{eval-rst}
+.. automodapi:: orbit.time_dep
+ :no-heading:
+```
+
diff --git a/doc/source/reference/orbit.utils.md b/doc/source/reference/orbit.utils.md
new file mode 100644
index 00000000..feaf05a0
--- /dev/null
+++ b/doc/source/reference/orbit.utils.md
@@ -0,0 +1,7 @@
+# orbit.utils
+
+```{eval-rst}
+.. automodapi:: orbit.utils
+ :no-heading:
+```
+
diff --git a/doc/source/reference/py.md b/doc/source/reference/py.md
new file mode 100644
index 00000000..8e4c7fe5
--- /dev/null
+++ b/doc/source/reference/py.md
@@ -0,0 +1,32 @@
+# Python API Reference
+
+```{eval-rst}
+.. toctree::
+ :maxdepth: 2
+
+ orbit.aperture
+ orbit.bumps
+ orbit.bunch_generators
+ orbit.bunch_utils
+ orbit.collimation
+ orbit.core
+ orbit.diagnostics
+ orbit.errors
+ orbit.fieldtracker
+ orbit.foils
+ orbit.impedances
+ orbit.injection
+ orbit.kickernodes
+ orbit.lattice
+ orbit.matching
+ orbit.matrix_lattice
+ orbit.orbit_correction
+ orbit.parsers
+ orbit.py_linac
+ orbit.rf_cavities
+ orbit.space_charge
+ orbit.teapot
+ orbit.teapot_base
+ orbit.time_dep
+ orbit.utils
+```
diff --git a/py/orbit/aperture/__init__.py b/py/orbit/aperture/__init__.py
index cf0f61fa..4289ff27 100644
--- a/py/orbit/aperture/__init__.py
+++ b/py/orbit/aperture/__init__.py
@@ -8,8 +8,10 @@
from .ApertureLatticeModifications import addTeapotApertureNode
from .ApertureLatticeRangeModifications import addCircleApertureSet, addEllipseApertureSet, addRectangleApertureSet
+from orbit.core.aperture import Aperture
+
# from TeapotApertureShapeNode import CircleApertureNode
__all__ = []
__all__.append("Aperture")
-__all__.append("checkBunch")
+# __all__.append("checkBunch") # non-static method of the Aperture Class
diff --git a/py/orbit/bunch_utils/__init__.py b/py/orbit/bunch_utils/__init__.py
index 88b43d5f..42ea363e 100644
--- a/py/orbit/bunch_utils/__init__.py
+++ b/py/orbit/bunch_utils/__init__.py
@@ -5,14 +5,25 @@
## - ParticleIdNumber - Class for adding unique id numbers to particle in a bunch
#
-from orbit.bunch_utils.particleidnumber import ParticleIdNumber
+from .particleidnumber import ParticleIdNumber
# This guards against missing numpy.
# Should be imporved with some meaningful (and MPI friendly?) warning printed out.
try:
- from orbit.bunch_utils.serialize import collect_bunch, save_bunch, load_bunch
-except:
+ from .serialize import collect_bunch, save_bunch, load_bunch
+ from .serialize import BunchDict, SyncPartDict
+ from .serialize import FileHandler, NumPyHandler
+except ImportError:
pass
__all__ = []
-__all__.append("addParticleIdNumbers")
+# __all__.append("addParticleIdNumbers") # doesn't exist
+__all__.append("ParticleIdNumber")
+__all__.append("collect_bunch")
+__all__.append("save_bunch")
+__all__.append("load_bunch")
+__all__.append("BunchDict")
+__all__.append("SyncPartDict")
+__all__.append("FileHandler")
+__all__.append("NumPyHandler")
+
diff --git a/py/orbit/bunch_utils/serialize.py b/py/orbit/bunch_utils/serialize.py
index 1a8a0e3b..0cbea0f2 100644
--- a/py/orbit/bunch_utils/serialize.py
+++ b/py/orbit/bunch_utils/serialize.py
@@ -10,6 +10,23 @@
class SyncPartDict(TypedDict):
+ """A dictionary containing the attributes of the synchronous particle.
+
+ Attributes
+ ----------
+ coords : NDArray[np.float64]
+ The coordinates (x, px, y, py, z, dE) of the synchronous particle.
+ kin_energy : float
+ The kinetic energy of the synchronous particle.
+ momentum : float
+ The momentum of the synchronous particle.
+ beta : float
+ The beta of the synchronous particle.
+ gamma : float
+ The gamma of the synchronous particle.
+ time : float
+ The time of the synchronous particle.
+ """
coords: NDArray[np.float64]
kin_energy: np.float64
momentum: np.float64
@@ -19,13 +36,32 @@ class SyncPartDict(TypedDict):
class BunchDict(TypedDict):
+ """A dictionary containing the attributes of a PyOrbit::Bunch object.
+
+ Attributes
+ ----------
+ coords : NDArray[np.float64]
+ The coordinates (x, px, y, py, z, dE) of the particles in the bunch.
+ sync_part : SyncPartDict
+ The attributes of the synchronous particle.
+ attributes : dict[str, np.float64 | np.int32]
+ Other attributes of the bunch.
+ """
coords: NDArray[np.float64]
sync_part: SyncPartDict
attributes: dict[str, np.float64 | np.int32]
class FileHandler(Protocol):
- """Protocol for file handlers to read/write bunch data."""
+ """Protocol for file handlers to read/write bunch data.
+
+ Methods
+ _______
+ read() -> BunchDict:
+ Reads the bunch data from the specified directory and returns it as a dictionary.
+ write(bunch: BunchDict) -> None:
+ Writes the bunch data to the specified directory.
+ """
def __init__(self, *args: Any, **kwargs: Any) -> None: ...
@@ -36,15 +72,28 @@ def write(self, bunch: BunchDict) -> None: ...
class NumPyHandler:
"""Handler implementing the FileHandler protocol for NumPy binary files.
- This handler will create two files in the directory passed to the constructor:
- - coords.npy: A memory-mapped NumPy array containing the bunch coordinates.
- - attributes.npz: A NumPy archive containing data related to the synchronous particle and other bunch attributes.
+
+ Attributes
+ ----------
+ _coords_fname : str
+ The name of the file containing the bunch coordinates (default: "coords.npy").
+ _attributes_fname : str
+ The name of the file containing data related to the synchronous particle and other bunch attributes (default: "attributes.npz").
"""
_coords_fname = "coords.npy"
_attributes_fname = "attributes.npz"
- def __init__(self, dir_name: str | pathlib.Path):
+ def __init__(self, dir_name: str | os.PathLike):
+ """Constructor for the NumPyHandler class.
+
+ Parameters
+ ----------
+ dir_name
+ The directory in which to store the bunch data.
+
+ """
+
if isinstance(dir_name, str):
dir_name = pathlib.Path(dir_name)
self._dir_name = dir_name
@@ -77,41 +126,29 @@ def write(self, bunch: BunchDict) -> None:
def collect_bunch(
- bunch: Bunch, output_dir: str | pathlib.Path = "/tmp", return_memmap: bool = True
+ bunch: Bunch, output_dir: str | os.PathLike = "/tmp", return_memmap: bool = True
) -> BunchDict | None:
"""Collects attributes from a PyOrbit Bunch across all MPI ranks and returns it as a dictionary.
+
Parameters
----------
bunch : Bunch
The PyOrbit::Bunch object from which to collect attributes.
- output_dir : str | pathlib.Path, optional
- The director to use for temporary storage of the bunch coordinates on each MPI rank.
- If None, the bunch will be stored in "/tmp".
- Note: take care that the temporary files are created in a directory where all MPI ranks have write access.
+ output_dir : str | os.PathLike, optional
+ The director to use for temporary storage of the bunch coordinates on each MPI rank (default: "/tmp").
return_memmap : bool, optional
Return the bunch coordinates as a memory-mapped NumPy array, otherwise the
- entire array is copied into RAM and returned as normal NDArray. Default is True.
+ entire array is copied into RAM and returned as normal NDArray (default: True).
+
+ Note
+ ----
+ Take care that the temporary files are created in a directory which all MPI ranks have write access.
+
Returns
-------
BunchDict | None
A dictionary containing the collected bunch attributes. Returns None if not on the root MPI rank or if the global bunch size is 0.
- BunchDict structure:
- {
- "coords": NDArray[np.float64] of shape (N, 6) where N is the total number of macroparticles,
- and the 6 columns correspond to [x, xp, y, yp, z, dE] in units of [m, rad, m, rad, m, GeV], respectively.
- "sync_part": {
- "coords": NDArray[np.float64] of shape (3,),
- "kin_energy": np.float64,
- "momentum": np.float64,
- "beta": np.float64,
- "gamma": np.float64,
- "time": np.float64
- },
- "attributes": {
- : ,
- ...
- }
- }
+
Raises
------
FileNotFoundError
@@ -208,21 +245,24 @@ def collect_bunch(
def save_bunch(
bunch: Bunch | BunchDict,
- output_dir: str | pathlib.Path = "bunch_data/",
+ output_dir: str | os.PathLike = "bunch_data/",
Handler: type[FileHandler] = NumPyHandler,
) -> None:
"""Saves the collected bunch attributes to a specified directory.
+
Parameters
----------
bunch_dict : Bunch | BunchDict
The PyOrbit::Bunch object or the dictionary containing the collected bunch attributes.
output_dir : str, optional
- The directory where the bunch data files will be saved. Default is "bunch_data/".
+ The directory where the bunch data files will be saved (default: "bunch_data/").
Handler : FileHandler, optional
- The file handler class to use for writing the bunch data. Default is NumPyHandler.
+ The file handler class to use for writing the bunch data (default: NumPyHandler).
+
Returns
-------
None
+
Raises
------
ValueError
@@ -252,20 +292,23 @@ def save_bunch(
def load_bunch(
- input_dir: str | pathlib.Path, Handler: type[FileHandler] = NumPyHandler
+ input_dir: str | os.PathLike, Handler: type[FileHandler] = NumPyHandler
) -> tuple[Bunch, BunchDict]:
"""Loads the bunch attributes from a specified directory containing NumPy binary files.
+
Parameters
----------
- input_dir : str | pathlib.Path
+ input_dir : str | os.PathLike
The directory from which to load the bunch data files.
Handler : FileHandler, optional
- The file handler class to use for reading the bunch data. Default is NumPyHandler.
+ The file handler class to use for reading the bunch data (default: NumPyHandler).
See `orbit.bunch_utils.file_handler` for available handlers.
+
Returns
-------
BunchDict
A dictionary containing the loaded bunch attributes.
+
Raises
------
FileNotFoundError
diff --git a/py/orbit/errors/__init__.py b/py/orbit/errors/__init__.py
index 92110bcc..9fcf4d63 100644
--- a/py/orbit/errors/__init__.py
+++ b/py/orbit/errors/__init__.py
@@ -38,7 +38,7 @@
from orbit.errors.ErrorLatticeModifications import addErrorNodeAsChild_F
__all__ = []
-__all__.append("")
+# __all__.append("")
__all__.append("addErrorNode")
__all__.append("addErrorNodeAsChild")
__all__.append("addErrorNodeAsChild_I")
diff --git a/py/orbit/fieldtracker/__init__.py b/py/orbit/fieldtracker/__init__.py
index f2b2d390..3a42371f 100644
--- a/py/orbit/fieldtracker/__init__.py
+++ b/py/orbit/fieldtracker/__init__.py
@@ -3,12 +3,11 @@
##
## Classes:
-
-from . import FieldTracker
+from orbit.core.fieldtracker import FieldTracker
__all__ = []
__all__.append("FieldTracker")
-__all__.append("trackBunch")
-__all__.append("FieldParser3D")
-__all__.append("BGrid3D")
-__all__.append("setPathVariable")
+# __all__.append("trackBunch") # non-static method of the FieldTracker Class
+# __all__.append("FieldParser3D") # doesn't exist
+# __all__.append("BGrid3D") # non-static method of the FieldTracker Class
+# __all__.append("setPathVariable") # non-static method of the FieldTracker Class
diff --git a/py/orbit/orbit_correction/__init__.py b/py/orbit/orbit_correction/__init__.py
index 80f56875..22cec1f6 100644
--- a/py/orbit/orbit_correction/__init__.py
+++ b/py/orbit/orbit_correction/__init__.py
@@ -13,6 +13,6 @@
__all__ = []
-__all__.append("")
+# __all__.append("")
__all__.append("orbit")
__all__.append("correction")
diff --git a/py/orbit/py_linac/lattice/__init__.py b/py/orbit/py_linac/lattice/__init__.py
index cab3b3a7..85a9df80 100644
--- a/py/orbit/py_linac/lattice/__init__.py
+++ b/py/orbit/py_linac/lattice/__init__.py
@@ -68,9 +68,9 @@
__all__.append("RF_Cavity")
__all__.append("Sequence")
-__all__.append("LinacStructureTree")
-__all__.append("LinacStructureSeq")
-__all__.append("LinacStuctureNode")
+# __all__.append("LinacStructureTree") # doesn't exist
+# __all__.append("LinacStructureSeq")
+# __all__.append("LinacStuctureNode")
__all__.append("BaseRF_Gap")
__all__.append("AxisFieldRF_Gap")
diff --git a/py/orbit/py_linac/overlapping_fields/overlapping_quad_fields_lib.py b/py/orbit/py_linac/overlapping_fields/overlapping_quad_fields_lib.py
index 875e5183..747288f6 100644
--- a/py/orbit/py_linac/overlapping_fields/overlapping_quad_fields_lib.py
+++ b/py/orbit/py_linac/overlapping_fields/overlapping_quad_fields_lib.py
@@ -88,10 +88,12 @@ def getFuncDerivative(self, z):
class EngeFunction(AbstractQuadFieldSourceFunction):
"""
- The Enge function with parameters from Berz's paper
- M.Berz, B. Erdelyn, K.Makino
- Fringe Field Effects in Small Rings of Large Acceptance
- Phys. Rev STAB, V3, 124001(2000)
+ The Enge function with parameters from Berz's paper [1]_.
+
+ References
+ ----------
+ .. [1] M. Berz, B. Erdélyi, and K. Makino, “Fringe field effects in small rings of large acceptance,” Phys. Rev. ST Accel. Beams, vol. 3, no. 12, p. 124001, Dec. 2000, doi: 10.1103/PhysRevSTAB.3.124001.
+
"""
def __init__(self, length_param, acceptance_diameter_param, cutoff_level=0.01):
diff --git a/py/orbit/py_linac/rf_field_readers/SuperFish_3D_RF_FieldReader.py b/py/orbit/py_linac/rf_field_readers/SuperFish_3D_RF_FieldReader.py
index 555bfd66..2866d644 100644
--- a/py/orbit/py_linac/rf_field_readers/SuperFish_3D_RF_FieldReader.py
+++ b/py/orbit/py_linac/rf_field_readers/SuperFish_3D_RF_FieldReader.py
@@ -4,7 +4,7 @@
from orbit.core import orbit_mpi
from orbit.core.orbit_mpi import mpi_comm, mpi_datatype, mpi_op
-from spacecharge import Grid2D
+from orbit.core.spacecharge import Grid2D
from orbit.core.orbit_utils import Function, SplineCH, GaussLegendreIntegrator, Polynomial
from orbit.utils.fitting import PolynomialFit
diff --git a/py/orbit/py_linac/rf_field_readers/__init__.py b/py/orbit/py_linac/rf_field_readers/__init__.py
index 47470b31..9921bf1d 100644
--- a/py/orbit/py_linac/rf_field_readers/__init__.py
+++ b/py/orbit/py_linac/rf_field_readers/__init__.py
@@ -10,12 +10,12 @@
## 3D filed. It generates the field on the axis for RF_AxisFieldAnalysis
# -------------------------------------------------------------------------
-from RF_AxisFieldAnalysis import RF_AxisFieldAnalysis
-from SuperFish_3D_RF_FieldReader import SuperFish_3D_RF_FieldReader
+from .RF_AxisFieldAnalysis import RF_AxisFieldAnalysis
+from .SuperFish_3D_RF_FieldReader import SuperFish_3D_RF_FieldReader
__all__ = []
# Classes
__all__.append("RF_AxisFieldAnalysis")
-__all__.append("SuperFish_3D_RF_FiledReader")
+__all__.append("SuperFish_3D_RF_FieldReader")
diff --git a/py/orbit/rf_cavities/__init__.py b/py/orbit/rf_cavities/__init__.py
index 3bac2839..3c1b3120 100644
--- a/py/orbit/rf_cavities/__init__.py
+++ b/py/orbit/rf_cavities/__init__.py
@@ -10,6 +10,8 @@
from orbit.rf_cavities.RFNode import Frequency_RFNode
from orbit.rf_cavities.RFNode import Harmonic_RFNode
from orbit.rf_cavities.RFNode import Barrier_RFNode
+from orbit.rf_cavities.RFNode import BRhoDep_Harmonic_RFNode
+from orbit.rf_cavities.RFNode import SyncPhaseDep_Harmonic_RFNode
from orbit.rf_cavities.RFLatticeModifications import addRFNode
__all__ = []
diff --git a/py/orbit/teapot/__init__.py b/py/orbit/teapot/__init__.py
index 945450d4..ac2ab3d2 100644
--- a/py/orbit/teapot/__init__.py
+++ b/py/orbit/teapot/__init__.py
@@ -7,6 +7,7 @@
from .teapot import TEAPOT_Ring
from .teapot import BaseTEAPOT
from .teapot import BendTEAPOT
+from .teapot import BunchWrapTEAPOT
from .teapot import DriftTEAPOT
from .teapot import FringeFieldTEAPOT
from .teapot import KickTEAPOT
diff --git a/py/orbit/time_dep/__init__.py b/py/orbit/time_dep/__init__.py
index 16afb666..dbf50932 100644
--- a/py/orbit/time_dep/__init__.py
+++ b/py/orbit/time_dep/__init__.py
@@ -3,5 +3,8 @@
##
## Classes:
##
+
+from .time_dep import TIME_DEP_Lattice
+
__all__ = []
__all__.append("TIME_DEP_Lattice")
diff --git a/py/orbit/time_dep/time_dep.py b/py/orbit/time_dep/time_dep.py
index 2d8483d3..2bf34260 100644
--- a/py/orbit/time_dep/time_dep.py
+++ b/py/orbit/time_dep/time_dep.py
@@ -15,8 +15,8 @@
class TIME_DEP_Lattice(TEAPOT_Ring):
"""
The subclass of the TEAPOT_Lattice.
- TIME_DEP_Lattice has the ability to set time-dependent
- parameters to the Lattice.
+
+ TIME_DEP_Lattice has the ability to set time-dependent parameters to the Lattice.
Multi-turn track also available.
"""
diff --git a/py/orbit/utils/multiDimArray.py b/py/orbit/utils/multiDimArray.py
index 6f73c0c4..9dc80eaf 100644
--- a/py/orbit/utils/multiDimArray.py
+++ b/py/orbit/utils/multiDimArray.py
@@ -1,11 +1,25 @@
-def multiDimDoubleArray(*dims):
+def multiDimDoubleArray(*dims: int) -> list[float]:
"""
- Method. Creates multi-dimensional arrays with doubles, such as a[i][k][j].
- Some examples of the use of this function:
- a = multiDimArray(5,10,2)
- a = multiDimArray(*[5,10,2])
- a[1][2][1] = 0.
- By default all elements are initialized to 0.
+ Creates multi-dimensional arrays with doubles, such as a[i][k][j].
+
+ Parameters
+ ----------
+ dims : int
+
+ Returns
+ -------
+ list[float]
+
+ Note
+ ----
+ All elements are initialized to 0.
+
+ Examples
+ --------
+ >>> a = multiDimArray(5,10,2)
+ >>> a = multiDimArray(*[5,10,2]) # equivalent
+ >>> a[1][2][1]
+ 0.0
"""
res = []
if len(dims) == 1:
@@ -18,14 +32,24 @@ def multiDimDoubleArray(*dims):
return res
-def multiDimIntArray(*dims):
+def multiDimIntArray(*dims: int) -> list[int]:
"""
- Method. Creates multi-dimensional arrays with integers, such as a[i][k][j].
- Some examples of the use of this function:
- a = multiDimArray(5,10,2)
- a = multiDimArray(*[5,10,2])
- a[1][2][1] = 0
- By default all elements are initialized to 0.
+ Creates multi-dimensional arrays with integers, such as a[i][k][j].
+
+ Parameters
+ ----------
+ dims : int
+
+ Returns
+ -------
+ list[int]
+
+ Examples
+ --------
+ >>> a = multiDimArray(5,10,2)
+ >>> a = multiDimArray(*[5,10,2]) # equivalent
+ >>> a[1][2][1]
+ 0
"""
res = []
if len(dims) == 1:
diff --git a/src/mpi/orbit_mpi.cc b/src/mpi/orbit_mpi.cc
index 8a36065e..2dc97e71 100644
--- a/src/mpi/orbit_mpi.cc
+++ b/src/mpi/orbit_mpi.cc
@@ -5,6 +5,7 @@
#include
#include
+#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
/** A C wrapper around MPI_Init. */
int ORBIT_MPI_Init(){
int res = 0;
@@ -620,3 +621,4 @@ int ORBIT_MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count){
#endif
return res;
}
+#endif // !defined(DOXYGEN_SHOULD_SKIP_THIS)
diff --git a/src/orbit/BunchDiagnostics/BunchTwissAnalysis.cc b/src/orbit/BunchDiagnostics/BunchTwissAnalysis.cc
index 2063b6ae..0a361326 100644
--- a/src/orbit/BunchDiagnostics/BunchTwissAnalysis.cc
+++ b/src/orbit/BunchDiagnostics/BunchTwissAnalysis.cc
@@ -337,10 +337,6 @@ void BunchTwissAnalysis::computeBunchMoments(Bunch* bunch, int order, int disper
}
-
-
-
-/** Returns the centered correlation <(x-)*(y-)> = - * */
double BunchTwissAnalysis::getCorrelation(int ic, int jc){
if(ic < 0 || ic > 5 || jc < 0 || jc >5) return 0.;
return (corr_arr[ic+6*jc] - avg_arr[ic]* avg_arr[jc]);
diff --git a/src/orbit/BunchDiagnostics/BunchTwissAnalysis.hh b/src/orbit/BunchDiagnostics/BunchTwissAnalysis.hh
index df6e2b4b..deaa20ee 100644
--- a/src/orbit/BunchDiagnostics/BunchTwissAnalysis.hh
+++ b/src/orbit/BunchDiagnostics/BunchTwissAnalysis.hh
@@ -26,7 +26,16 @@ class BunchTwissAnalysis: public OrbitUtils::CppPyWrapper
/** Performs the Twiss analysis of the bunch */
void analyzeBunch(Bunch* bunch);
- /** Returns the centered correlation <(x-)*(y-)> = - * */
+ /**
+ * @brief Returns the centered correlation between two components.
+ *
+ * \f$\langle (x-\langle x\rangle)(y-\langle y\rangle)\rangle
+ * = \langle x y\rangle - \langle x\rangle\langle y\rangle\f$
+ *
+ * @param ic Index of the first component (x).
+ * @param jc Index of the second component (y).
+ * @return The centered correlation value as a double.
+ */
double getCorrelation(int ic, int jc);
/** Returns the average value for coordinate with index ic */
diff --git a/src/orbit/MaterialInteractions/numrecipes.cc b/src/orbit/MaterialInteractions/numrecipes.cc
index eadd37ee..a38dd327 100644
--- a/src/orbit/MaterialInteractions/numrecipes.cc
+++ b/src/orbit/MaterialInteractions/numrecipes.cc
@@ -29,9 +29,8 @@ namespace OrbitUtils{
return sin(x)*exp(-fac1*pow(2*p*sin(x/2), 2))/pow(sin(x/2),4);
}
-
int zbrak(float (*fx)(float, float, float, float), float x1, float x2,
- int n, float xb1[], float xb2[], int &nb, float param1,
+ int n, float *xb1, float *xb2, int &nb, float param1,
float param2, float param3)
{
int nbb, i;
@@ -54,7 +53,9 @@ namespace OrbitUtils{
}
#undef JMAX
+#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
#define JMAX 40
+#endif
float rtbis(float (*func)(float, float, float, float), float x1, float x2,
float xacc, float param1, float param2, float param3)
@@ -134,8 +135,10 @@ namespace OrbitUtils{
#undef EPS
#undef JMAX
+#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
#define EPS 1.0e-6
#define JMAX 20
+#endif
float qsimp(float (*func)(float, float, float), float a, float b,
float p, float fac1)
@@ -164,7 +167,9 @@ namespace OrbitUtils{
/* note #undef's at end of file */
+#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
#define FUNC(x, p, fac1) ((*rfunc)(x, p, fac1))
+#endif
float trapzd(float (*rfunc)(float, float, float), float a,
float b, int n, float p, float fac1)
diff --git a/src/orbit/MaterialInteractions/numrecipes.hh b/src/orbit/MaterialInteractions/numrecipes.hh
index 25f884e0..8059db80 100644
--- a/src/orbit/MaterialInteractions/numrecipes.hh
+++ b/src/orbit/MaterialInteractions/numrecipes.hh
@@ -16,7 +16,54 @@ namespace OrbitUtils{
float fstep(float s, float r_o, float pr_o, float theta);
float rfunc(float x, float p, float fac1);
- int zbrak(float (*fx)(float, float, float, float), float x1, float x2, int n, float xb1[], float xb2[], int &nb, float param1,
+
+ /**
+ * @brief Bracket subintervals where a function changes sign.
+ *
+ * Scans the interval [x1, x2] by dividing it into @p n equal subintervals
+ * and records subinterval endpoints where the function @p fx changes sign
+ * (i.e., a root is bracketed).
+ *
+ * The function @p fx must have the signature:
+ * float fx(float x, float p1, float p2, float p3);
+ * It is evaluated at the grid points x1, x1 + dx, x1 + 2*dx, ..., x2,
+ * where dx = (x2 - x1) / n.
+ *
+ * When an interval [xb1[k], xb2[k]] is found such that fx(xb1[k]) and
+ * fx(xb2[k]) have opposite signs (fc*fp <= 0), the endpoints are stored
+ * in the output arrays xb1 and xb2 at the same index k (1-based indexing
+ * is used internally; the caller should account for this).
+ *
+ * @param fx Pointer to the function to examine. Signature:
+ * float fx(float x, float param1, float param2, float param3).
+ * @param x1 Left end of the search interval.
+ * @param x2 Right end of the search interval.
+ * @param n Number of equal subintervals to split [x1, x2] into.
+ * @param xb1 Output array to receive left endpoints of bracketing subintervals.
+ * Must be large enough to hold up to the capacity indicated by the
+ * integer referenced by @p nb (see @p nb description).
+ * @param xb2 Output array to receive right endpoints of bracketing subintervals.
+ * Same required capacity as @p xb1.
+ * @param nb Reference to an integer indicating the maximum number of bracket
+ * intervals the caller can accept on input; on return this integer
+ * is set to the actual number of brackets found (nb <= original nb).
+ * @param param1 First user parameter passed through to @p fx.
+ * @param param2 Second user parameter passed through to @p fx.
+ * @param param3 Third user parameter passed through to @p fx.
+ *
+ * @return Returns 0 on completion. If the number of found brackets reaches the
+ * input capacity (nb), the function returns immediately with xb1/xb2
+ * filled up to that capacity and nb set equal to that capacity.
+ *
+ * @note
+ * - The function uses sequential evaluations of @p fx and treats a zero or a
+ * sign change (fc*fp <= 0.0) as a bracket. Adjacent subintervals that both
+ * satisfy this condition will each be reported.
+ * - The implementation uses 1-based indexing internally when filling xb1/xb2.
+ * The caller should allocate arrays accordingly and interpret the filled
+ * entries consistent with the calling convention used in the surrounding code.
+ */
+ int zbrak(float (*fx)(float, float, float, float), float x1, float x2, int n, float *xb1, float *xb2, int &nb, float param1,
float param2, float param3);
float rtbis(float (*func)(float, float, float, float), float x1, float x2, float xacc, float param1, float param2, float param3);
float bessj0(float x);
diff --git a/src/spacecharge/UniformEllipsoidFieldCalculator.cc b/src/spacecharge/UniformEllipsoidFieldCalculator.cc
index 42fc6970..811eb52d 100644
--- a/src/spacecharge/UniformEllipsoidFieldCalculator.cc
+++ b/src/spacecharge/UniformEllipsoidFieldCalculator.cc
@@ -15,6 +15,7 @@
using namespace OrbitUtils;
//macros for max and min
+#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
#ifndef max
#define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
#endif
@@ -22,6 +23,7 @@ using namespace OrbitUtils;
#ifndef min
#define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
#endif
+#endif
/** Constructor. There is no parameters */
UniformEllipsoidFieldCalculator::UniformEllipsoidFieldCalculator(): CppPyWrapper(NULL)
diff --git a/src/utils/Random.cc b/src/utils/Random.cc
index c19bafca..4725232a 100644
--- a/src/utils/Random.cc
+++ b/src/utils/Random.cc
@@ -21,6 +21,7 @@
using namespace OrbitUtils;
// By default the random generator is initialized using a random seed (current time)
+#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
std::mt19937 mt(time(0));
void Random::seed(int seed){
@@ -31,3 +32,4 @@ void Random::seed(int seed){
double Random::ran1(){
return ((double) mt() / (mt.max()));
}
+#endif