From 4f6f8d67245f9174a39553e2b2409e1b6ec1f393 Mon Sep 17 00:00:00 2001
From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com>
Date: Fri, 7 Aug 2026 11:59:25 +0200
Subject: [PATCH 1/7] docs: modernize documentation structure
---
.github/workflows/docs.yml | 83 ++++----
docs/source/_static/css/custom.css | 38 ++--
docs/source/_templates/package.rst | 5 +-
docs/source/analyses/index.rst | 82 ++++++++
docs/source/analyses/momentum.rst | 42 ++++
docs/source/analyses/msd.rst | 61 ++++++
docs/source/analyses/rdf.rst | 61 ++++++
docs/source/analyses/vacf.rst | 64 ++++++
docs/source/analyses/vibrations.rst | 55 +++++
docs/source/conf.py | 192 +++++++++---------
docs/source/data/index.rst | 88 ++++++++
docs/source/developerGuide/developerGuide.rst | 150 +++++++-------
docs/source/getting-started.rst | 99 +++++++++
docs/source/index.rst | 111 ++++++++--
docs/source/reference/api.rst | 67 ++++++
docs/source/reference/cli.rst | 96 +++++++++
docs/source/reference/index.rst | 34 ++++
docs/source/userGuide/analysisOutputFiles.rst | 5 +-
docs/source/userGuide/inputFile.rst | 139 ++++++++++---
docs/source/userGuide/userGuide.rst | 169 ++-------------
pyproject.toml | 8 +-
21 files changed, 1206 insertions(+), 443 deletions(-)
create mode 100644 docs/source/analyses/index.rst
create mode 100644 docs/source/analyses/momentum.rst
create mode 100644 docs/source/analyses/msd.rst
create mode 100644 docs/source/analyses/rdf.rst
create mode 100644 docs/source/analyses/vacf.rst
create mode 100644 docs/source/analyses/vibrations.rst
create mode 100644 docs/source/data/index.rst
create mode 100644 docs/source/getting-started.rst
create mode 100644 docs/source/reference/api.rst
create mode 100644 docs/source/reference/cli.rst
create mode 100644 docs/source/reference/index.rst
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 8480df72..add34a8d 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -1,62 +1,49 @@
-# Sample workflow for building and deploying a Jekyll site to GitHub Pages
name: Docs
on:
- # Runs on pushes targeting the default branch
push:
- branches:
- - '*'
-
- # Allows you to run this workflow manually from the Actions tab
+ branches: [main, dev]
+ pull_request:
+ branches: [main, dev]
workflow_dispatch:
-# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
- contents: write
- pages: write
-
-# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
-# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
-concurrency:
- group: "pages"
- cancel-in-progress: false
+ contents: read
jobs:
- # Build job
- build:
+ build-docs:
runs-on: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup Python
- uses: actions/setup-python@v5
+ - uses: actions/checkout@v7
with:
- python-version: 3.12
+ fetch-depth: 0
+ - uses: actions/setup-python@v7
+ with:
+ python-version: "3.12"
cache: pip
-
- - name: Requirements
- run: |
- sudo apt-get update
- sudo apt-get install -y python3-sphinx
- python -m pip install --upgrade pip
- python -m pip install -e ".[docs]"
-
- - name: Build
- run: |
- cd docs
- make clean
- rm -f source/code/*
- bash autodoc.sh
- make html
- cd build/html
- touch .nojekyll
- shell: bash
-
- # Deployment job
- - name: deploy
- uses: JamesIves/github-pages-deploy-action@releases/v4
+ - name: Install the package and documentation dependencies
+ run: python -m pip install -e ".[docs]"
+ - name: Build the documentation
+ run: python -m sphinx -W --keep-going -b html docs/source docs/build/html
+ - name: Upload Pages artifact
+ uses: actions/upload-pages-artifact@v5
with:
- branch: gh-pages # The branch the action should deploy to.
- folder: docs/build/html # The folder the action should deploy.
- if: github.ref_name == 'main' # Only deploy on pushes to the main branch
+ path: docs/build/html
+
+ deploy-docs:
+ needs: build-docs
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+ runs-on: ubuntu-latest
+ concurrency:
+ group: pages
+ cancel-in-progress: false
+ permissions:
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v5
diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css
index d4bed75f..a7e33447 100644
--- a/docs/source/_static/css/custom.css
+++ b/docs/source/_static/css/custom.css
@@ -1,34 +1,36 @@
-@import url("theme.css");
-
-.wy-nav-content {
- max-width: 80%;
+.sidebar-logo {
+ width: 4rem;
}
-dl.py.class {
- dt.sig.sig-object.py {
- display: block !important;
- }
+.sidebar-brand-text {
+ font-weight: 700;
+ letter-spacing: 0;
}
-.py.property {
- display: block !important;
+.sd-card {
+ border-radius: 4px;
+ box-shadow: none;
}
-.sig.sig-object.py dl {
- margin-block-end: 0.0em;
+code.literal {
+ border-radius: 2px;
+}
- & dd {
- margin-bottom: 0.0em;
- }
+.table-wrapper {
+ overflow-x: auto;
}
-.wy-table-responsive table.analysis-output-columns {
+table.analysis-output-columns {
min-width: 640px;
width: 100%;
}
-.wy-table-responsive table.analysis-output-columns th,
-.wy-table-responsive table.analysis-output-columns td {
+table.analysis-output-columns th,
+table.analysis-output-columns td {
vertical-align: top;
white-space: normal;
}
+
+.pq-command-table td:first-child {
+ white-space: nowrap;
+}
diff --git a/docs/source/_templates/package.rst b/docs/source/_templates/package.rst
index fadf61ee..195448b0 100644
--- a/docs/source/_templates/package.rst
+++ b/docs/source/_templates/package.rst
@@ -1,4 +1,5 @@
-{# The :autogenerated: tag is picked up by breadcrumbs.html to suppress "Edit on Github" link #}
+{# Generated packages stay outside the curated user-facing navigation. #}
+:orphan:
:autogenerated:
{{ name }}
@@ -116,4 +117,4 @@
Reference
---------
-{%- endif %}
\ No newline at end of file
+{%- endif %}
diff --git a/docs/source/analyses/index.rst b/docs/source/analyses/index.rst
new file mode 100644
index 00000000..b5e891c4
--- /dev/null
+++ b/docs/source/analyses/index.rst
@@ -0,0 +1,82 @@
+Analyses
+========
+
+PQAnalysis covers structural organization, translational dynamics,
+time-correlation spectra, molecular normal modes and conservation diagnostics.
+Choose the observable from the physical question and from the data recorded by
+the simulation.
+
+.. grid:: 1 2 3 3
+ :gutter: 2
+
+ .. grid-item-card:: Radial distribution
+ :link: rdf
+ :link-type: doc
+
+ Pair structure, preferred separations and coordination numbers.
+
+ .. grid-item-card:: Mean square displacement
+ :link: msd
+ :link-type: doc
+
+ Translational motion and Einstein-relation diffusion estimates.
+
+ .. grid-item-card:: VACF and spectra
+ :link: vacf
+ :link-type: doc
+
+ Velocity or charge-flux correlation and frequency-domain spectra.
+
+ .. grid-item-card:: Vibrational analysis
+ :link: vibrations
+ :link-type: doc
+
+ Hessian normal modes, wavenumbers, force constants and IR intensities.
+
+ .. grid-item-card:: Total momentum
+ :link: momentum
+ :link-type: doc
+
+ Frame-resolved linear momentum and center-of-mass drift diagnostics.
+
+ .. grid-item-card:: Output schemas
+ :link: ../userGuide/analysisOutputFiles
+ :link-type: doc
+
+ Exact columns, units, normalizations and format conversion behavior.
+
+Choose by input data
+--------------------
+
+.. list-table:: Analysis inputs and primary observables
+ :header-rows: 1
+ :widths: 24 32 44
+
+ * - Analysis
+ - Required physical data
+ - Primary observable
+ * - RDF
+ - Positions and periodic cell
+ - :math:`g_{AB}(r)` and cumulative coordination
+ * - MSD
+ - Positions and periodic cell
+ - :math:`\langle |\mathbf{r}(t)-\mathbf{r}(0)|^2\rangle`
+ * - VACF
+ - Velocities and frame time step
+ - Normalized :math:`C_v(t)` and its spectrum
+ * - Vibrations
+ - Structure, masses and Cartesian Hessian
+ - Normal-mode wavenumbers and force constants
+ * - Momentum
+ - Velocities and atomic masses
+ - :math:`|\sum_i m_i\mathbf{v}_i|` per frame
+
+.. toctree::
+ :hidden:
+ :maxdepth: 1
+
+ rdf
+ msd
+ vacf
+ vibrations
+ momentum
diff --git a/docs/source/analyses/momentum.rst b/docs/source/analyses/momentum.rst
new file mode 100644
index 00000000..18675d67
--- /dev/null
+++ b/docs/source/analyses/momentum.rst
@@ -0,0 +1,42 @@
+Total Linear Momentum
+=====================
+
+For every velocity frame, PQAnalysis evaluates the selected atoms' total
+linear momentum,
+
+.. math::
+
+ \mathbf{P}(t) = \sum_i m_i\mathbf{v}_i(t),
+
+and writes its scaled norm. This is a diagnostic for center-of-mass drift and
+momentum conservation, not a substitute for inspecting the thermostat,
+constraints or integration scheme.
+
+Run the diagnostic
+------------------
+
+.. code-block:: console
+
+ $ pqanalysis check_momentum velocity.vel \
+ --selection all \
+ --output momentum.dat
+
+The default scale of ``1e-15`` converts PQ velocity-trajectory values from
+amu Angstrom s\ :sup:`-1` to amu Angstrom fs\ :sup:`-1`. Use ``--scale`` when
+the input convention differs.
+
+Interpretation
+--------------
+
+The output contains a one-based frame index and the scaled momentum norm. A
+systematic increase can indicate center-of-mass drift. Oscillatory or noisy
+behavior must be interpreted relative to the total mass, velocity scale and
+numerical precision.
+
+PQ velocity trajectories are parsed in single precision. Norms below roughly
+``1e-7 * sum_i(m_i * |v_i|) * scale`` are therefore parsing noise rather than
+resolved physical drift.
+
+See :ref:`analysis-output-momentum` for the output schema. Python workflows
+can call :func:`PQAnalysis.analysis.momentum.api.check_momentum` or use
+:class:`PQAnalysis.analysis.momentum.momentum.Momentum` directly.
diff --git a/docs/source/analyses/msd.rst b/docs/source/analyses/msd.rst
new file mode 100644
index 00000000..8698a806
--- /dev/null
+++ b/docs/source/analyses/msd.rst
@@ -0,0 +1,61 @@
+Mean Square Displacement
+========================
+
+The mean square displacement measures translational motion over a lag time.
+For Cartesian component :math:`\alpha`, PQAnalysis evaluates multiple time
+origins according to
+
+.. math::
+
+ \mathrm{MSD}_{\alpha}(\tau) =
+ \left\langle [r_{i\alpha}(t+\tau)-r_{i\alpha}(t)]^2 \right\rangle_{i,t}.
+
+Coordinates are unwrapped with the periodic cell before displacements are
+accumulated.
+
+Minimal input
+-------------
+
+.. code-block:: text
+
+ traj_files = trajectory.xyz
+ target_selection = O
+ out_file = msd.dat
+ window = 1000
+ gap = 10
+ time_step = 0.001
+ fit_window = 200
+
+.. code-block:: console
+
+ $ pqanalysis msd msd.in
+
+``window`` is the largest lag in frames and must be divisible by ``gap``.
+``gap`` controls the spacing between time origins. ``time_step`` is expressed
+in ps and enables diffusion fitting; ``fit_window`` selects the trailing
+points used by that fit.
+
+Interpretation
+--------------
+
+The output contains the lag index and the x, y and z components in
+Angstrom squared. Their sum is the total three-dimensional MSD. In an
+isotropic diffusive regime,
+
+.. math::
+
+ D = \frac{1}{6}\frac{d}{dt}\mathrm{MSD}_{\mathrm{total}}(t).
+
+PQAnalysis also fits each Cartesian component with the corresponding
+one-dimensional factor. The resulting coefficients, uncertainties and
+:math:`R^2` values are written to the log file in m\ :sup:`2`/s. A fit is
+physically meaningful only over a linear diffusive interval; short-time
+ballistic motion and poorly sampled long lags should not be included blindly.
+
+Output and API
+--------------
+
+See :ref:`analysis-output-msd` for the exact table layout. The input-file entry
+point is :func:`PQAnalysis.analysis.msd.api.msd`; direct workflows can use
+:class:`PQAnalysis.analysis.msd.msd.MSD` and inspect its total MSD and fit
+results.
diff --git a/docs/source/analyses/rdf.rst b/docs/source/analyses/rdf.rst
new file mode 100644
index 00000000..63809510
--- /dev/null
+++ b/docs/source/analyses/rdf.rst
@@ -0,0 +1,61 @@
+Radial Distribution Function
+============================
+
+The radial distribution function measures the probability of finding a target
+atom at distance :math:`r` from a reference atom relative to an ideal gas at
+the same effective target density. For histogram bin :math:`i`, PQAnalysis
+uses
+
+.. math::
+
+ g_i = \frac{H_i}{\rho_T N_R N_F \Delta V_i},
+
+where :math:`H_i` is the eligible pair count, :math:`\rho_T` the target number
+density, :math:`N_R` the number of reference atoms, :math:`N_F` the number of
+frames and :math:`\Delta V_i` the spherical-shell volume.
+
+Minimal input
+-------------
+
+.. code-block:: text
+
+ traj_files = trajectory.xyz
+ reference_selection = O
+ target_selection = H
+ delta_r = 0.05
+ r_max = 8.0
+ out_file = rdf.dat
+
+.. code-block:: console
+
+ $ pqanalysis rdf rdf.in
+
+``restart_file`` and ``moldescriptor_file`` are unnecessary for a basic
+species RDF. They are required when ``no_intra_molecular = True`` is used to
+exclude pairs belonging to the same molecule. PQAnalysis can infer the usual
+PQ companion filenames when they are beside the trajectory.
+
+Interpretation
+--------------
+
+* Peaks mark preferred pair separations; minima separate coordination shells.
+* :math:`g(r) \approx 1` indicates bulk-like, uncorrelated pair density at that
+ distance.
+* The cumulative coordination column gives the mean number of eligible target
+ atoms per reference atom inside the current upper bin edge.
+* Self pairs are excluded. Intramolecular pairs are included unless molecular
+ topology is supplied and explicitly excluded.
+
+Normalization, finite-size effects, selection definitions and trajectory
+sampling should be considered before comparing RDFs from different systems.
+
+Output and API
+--------------
+
+See :ref:`analysis-output-rdf` for the five output columns and their exact
+normalization. The main Python entry point is
+:func:`PQAnalysis.analysis.rdf.api.rdf`; lower-level calculations use
+:class:`PQAnalysis.analysis.rdf.rdf.RDF`.
+
+The complete input-key table is documented with
+:class:`PQAnalysis.analysis.rdf.rdf_input_file_reader.RDFInputFileReader`.
diff --git a/docs/source/analyses/vacf.rst b/docs/source/analyses/vacf.rst
new file mode 100644
index 00000000..b4284dd2
--- /dev/null
+++ b/docs/source/analyses/vacf.rst
@@ -0,0 +1,64 @@
+VACF and Spectra
+================
+
+The normalized velocity autocorrelation function describes how rapidly atomic
+velocities lose memory of their initial direction:
+
+.. math::
+
+ C_v(t) =
+ \frac{\left\langle \sum_i \mathbf{v}_i(0)\cdot\mathbf{v}_i(t)\right\rangle}
+ {\left\langle \sum_i \mathbf{v}_i(0)\cdot\mathbf{v}_i(0)\right\rangle}.
+
+PQAnalysis can transform the correlation to a wavenumber-domain spectrum. If
+static or time-dependent partial charges are supplied, it correlates
+:math:`q_i\mathbf{v}_i` instead, producing a charge-flux spectrum that
+approximates an infrared spectrum.
+
+Minimal input
+-------------
+
+.. code-block:: text
+
+ traj_files = trajectory.vel
+ target_selection = all
+ out_file = vacf.dat
+ time_step = 0.001
+ window = 2500
+ gap = 5
+ spectrum_file = spectrum.dat
+ ftsize = 5000
+ window_function = exponential
+ window_param = 4.0
+
+.. code-block:: console
+
+ $ pqanalysis vacf vacf.in
+
+The time step is specified in ps. ``window_function`` accepts
+``exponential``, ``hann`` and ``blackman``. The default sliding-origin method
+matches the legacy calculation; ``method = fft`` selects a denser-origin
+Wiener-Khinchin estimator.
+
+Interpretation
+--------------
+
+* A rapidly decaying VACF indicates fast velocity decorrelation.
+* Negative regions indicate backscattering or cage motion.
+* The frequency spectrum depends on the sampling interval, correlation length,
+ apodization window and zero-padding size.
+* Charge-flux spectra require physically meaningful partial charges and should
+ not be interpreted as absolute IR intensities without further calibration.
+
+Output and API
+--------------
+
+See :ref:`analysis-output-vacf` for correlation and spectrum columns. The
+input-file entry point is :func:`PQAnalysis.analysis.vacf.api.vacf`. Direct
+calculations use :class:`PQAnalysis.analysis.vacf.vacf.VACF`, while
+:func:`PQAnalysis.analysis.vacf.spectrum.vacf_spectrum` performs the spectral
+transform.
+
+Discrete line spectra can be broadened independently with
+``pqanalysis build_spectrum``; see :ref:`analysis-output-spectrum` for its
+output convention.
diff --git a/docs/source/analyses/vibrations.rst b/docs/source/analyses/vibrations.rst
new file mode 100644
index 00000000..fb05df81
--- /dev/null
+++ b/docs/source/analyses/vibrations.rst
@@ -0,0 +1,55 @@
+Vibrational Analysis
+====================
+
+Vibrational analysis diagonalizes the mass-weighted Cartesian Hessian. Its
+eigenvectors define normal modes and its eigenvalues determine signed
+wavenumbers. Negative wavenumbers represent imaginary modes associated with
+negative curvature of the potential-energy surface.
+
+Minimal input
+-------------
+
+.. code-block:: text
+
+ structure_file = structure.rst
+ hessian_file = hessian.dat
+ out_file = wavenumbers.dat
+ normal_modes_file = normal_modes.dat
+ modes_file = modes.xyz
+ modes = positive
+ unit = kcal
+ hessian_sign = auto
+
+.. code-block:: console
+
+ $ pqanalysis vibrations vibrations.in
+
+``structure_file`` may be a PQ restart or a single-frame XYZ file. ``unit``
+describes the Hessian energy unit and accepts ``kcal``, ``hartree`` or ``ev``.
+``hessian_sign = auto`` evaluates both supported sign conventions and chooses
+the one with more non-negative vibrational modes.
+
+Scientific checks
+-----------------
+
+* A stable, fully optimized minimum should not contain genuine imaginary
+ internal modes. Small values can arise from incomplete optimization or
+ numerical noise.
+* Translational and rotational near-zero modes depend on boundary conditions,
+ molecular geometry and numerical precision.
+* IR intensities require a ``moldescriptor_file`` containing partial charges.
+* The Hessian coordinate order, structure atom order and selected unit must
+ agree exactly.
+
+Mode output
+-----------
+
+``normal_modes_file`` stores the dimensionless Cartesian mode matrix.
+``modes_prefix`` writes sinusoidal multi-frame XYZ animations, while
+``modes_file`` writes one extended-XYZ image per selected mode with vectors and
+metadata. Explicit mode numbers are one-based.
+
+See :ref:`analysis-output-vibrations` for every table and file schema. The main
+entry point is :func:`PQAnalysis.analysis.vibrational.api.vibrations`; direct
+calculations use
+:func:`PQAnalysis.analysis.vibrational.vibrational_analysis.calculate_from_system`.
diff --git a/docs/source/conf.py b/docs/source/conf.py
index d7f93d0e..94aa9ca8 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -1,43 +1,43 @@
-# 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
-
-# -- Project information -----------------------------------------------------
-# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+"""Sphinx configuration for the PQAnalysis documentation."""
import sys
-import os
+from pathlib import Path
+
+
+SOURCE_DIR = Path(__file__).resolve().parent
+DOCS_DIR = SOURCE_DIR.parent
+PROJECT_ROOT = DOCS_DIR.parent
-sys.path.insert(0, os.path.abspath('../../'))
+sys.path.insert(0, str(PROJECT_ROOT))
-project = 'PQAnalysis'
-copyright = '2023, Jakob Gamper, Josef M. Gallmetzer, Clarissa A. Seidler'
-author = 'Jakob Gamper, Josef M. Gallmetzer, Clarissa A. Seidler'
+project = "PQAnalysis"
+author = "the PQAnalysis authors"
+copyright = "2023-2026, the PQAnalysis authors"
-# -- General configuration ---------------------------------------------------
-# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+try:
+ from PQAnalysis import __version__ as release
+except Exception: # pragma: no cover - package may be absent in a bare checkout
+ release = ""
+version = release
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
extensions = [
- 'sphinx.ext.autodoc',
- 'sphinx.ext.intersphinx',
- 'sphinx.ext.todo',
- 'sphinx.ext.coverage',
- 'sphinx.ext.mathjax',
- 'sphinx.ext.ifconfig',
- 'sphinx.ext.viewcode',
- 'sphinx.ext.napoleon',
- 'sphinx.ext.autosummary',
- 'sphinx_sitemap',
- 'sphinx.ext.inheritance_diagram',
- 'myst_parser',
+ "sphinx.ext.autodoc",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.todo",
+ "sphinx.ext.coverage",
+ "sphinx.ext.mathjax",
+ "sphinx.ext.ifconfig",
+ "sphinx.ext.viewcode",
+ "sphinx.ext.napoleon",
+ "sphinx.ext.autosummary",
+ "sphinx.ext.inheritance_diagram",
+ "sphinx_sitemap",
+ "myst_parser",
+ "sphinx_copybutton",
+ "sphinx_design",
]
-# Napoleon settings
napoleon_google_docstring = True
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = False
@@ -50,92 +50,98 @@
napoleon_use_param = True
napoleon_use_rtype = True
-autoclass_content = 'both'
-autodoc_class_signature = 'mixed'
-autodoc_typehints_format = 'short'
-autodoc_member_order = 'alphabetical'
+autoclass_content = "both"
+autodoc_class_signature = "mixed"
+autodoc_typehints_format = "short"
+autodoc_member_order = "alphabetical"
maximum_signature_line_length = 50
add_module_names = False
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix(es) of source filenames.
-# You can specify multiple suffix as a list of string:
-source_suffix = ['.rst', '.md']
-
-# The master toctree document.
-master_doc = 'index'
+copybutton_prompt_text = r">>> |\.\.\. |\$ "
+copybutton_prompt_is_regexp = True
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This patterns also effect to html_static_path and html_extra_path
+templates_path = ["_templates"]
+source_suffix = {
+ ".rst": "restructuredtext",
+ ".md": "markdown",
+}
+master_doc = "index"
exclude_patterns = []
+highlight_language = "python"
-highlight_language = 'python'
-
-# -- Options for HTML output -------------------------------------------------
-# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+html_theme = "furo"
+html_title = "PQAnalysis"
+html_logo = "logo/PQAnalysis.png"
+html_favicon = "logo/PQAnalysis.png"
+html_static_path = ["_static"]
+html_css_files = ["css/custom.css"]
+html_baseurl = "https://molarverse.github.io/PQAnalysis/"
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-#
-html_theme = 'sphinx_rtd_theme'
-html_style = 'css/custom.css'
html_theme_options = {
- 'canonical_url': '',
- 'analytics_id': '', # Provided by Google in your dashboard
- 'prev_next_buttons_location': 'bottom',
- 'style_external_links': False,
-
- 'logo_only': False,
-
- # Toc options
- 'collapse_navigation': True,
- 'sticky_navigation': True,
- 'includehidden': True,
- 'titles_only': True,
- 'globaltoc_maxdepth': -1,
+ "sidebar_hide_name": False,
+ "light_css_variables": {
+ "color-brand-primary": "#1f718f",
+ "color-brand-content": "#176c8c",
+ },
+ "dark_css_variables": {
+ "color-brand-primary": "#65bddb",
+ "color-brand-content": "#65bddb",
+ },
+ "source_repository": "https://github.com/MolarVerse/PQAnalysis/",
+ "source_branch": "main",
+ "source_directory": "docs/source/",
+ "footer_icons": [
+ {
+ "name": "GitHub",
+ "url": "https://github.com/MolarVerse/PQAnalysis",
+ "html": (
+ ''
+ ),
+ "class": "",
+ },
+ ],
}
-html_logo = 'logo/PQAnalysis.png'
-# github_url = ''
-html_baseurl = 'https://molarverse.github.io/PQAnalysis/'
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
def show_inherited_mixins(app, what, name, obj, options, lines):
- """Show inherited mixins in the base classes of a class"""
+ """Show inherited mixins in the base classes of a class."""
- if what != 'class' or not hasattr(obj, '__bases__'):
+ if what != "class" or not hasattr(obj, "__bases__"):
return
for base in obj.__bases__:
- if base.__name__.endswith('Mixin'):
- options['inherited-members'] = True
+ if base.__name__.endswith("Mixin"):
+ options["inherited-members"] = True
def run_apidoc(app):
- """Generage API documentation"""
+ """Generate the complete package API reference."""
import better_apidoc
+
better_apidoc.APP = app
better_apidoc.main([
- 'better-apidoc',
- '-t',
- os.path.join('.', 'source', '_templates'),
- '--force',
- '--no-toc',
- '--separate',
- '-o',
- os.path.join('.', 'source', 'code'),
- os.path.join('..', 'PQAnalysis')
+ "better-apidoc",
+ "-t",
+ str(SOURCE_DIR / "_templates"),
+ "--force",
+ "--no-toc",
+ "--separate",
+ "-o",
+ str(SOURCE_DIR / "code"),
+ str(PROJECT_ROOT / "PQAnalysis"),
])
def setup(app):
- app.connect('autodoc-process-docstring', show_inherited_mixins)
- app.connect('builder-inited', run_apidoc)
+ app.connect("autodoc-process-docstring", show_inherited_mixins)
+ app.connect("builder-inited", run_apidoc)
diff --git a/docs/source/data/index.rst b/docs/source/data/index.rst
new file mode 100644
index 00000000..ad1e8fae
--- /dev/null
+++ b/docs/source/data/index.rst
@@ -0,0 +1,88 @@
+Data and Conversion
+===================
+
+PQAnalysis separates simulation data, analysis configuration and output-table
+serialization. File extensions select output formats, while input content and
+explicit engine options determine how trajectories are read.
+
+.. grid:: 1 2 2 2
+ :gutter: 2
+
+ .. grid-item-card:: Analysis input files
+ :link: ../userGuide/inputFile
+ :link-type: doc
+
+ Key-value grammar, scalar values, lists and comments.
+
+ .. grid-item-card:: Output tables
+ :link: ../userGuide/analysisOutputFiles
+ :link-type: doc
+
+ Native metadata, CSV, TSV, XVG, columns, units and normalization.
+
+ .. grid-item-card:: Command-line conversion
+ :link: ../reference/cli
+ :link-type: doc
+
+ Convert analysis tables, structures, trajectories and box data.
+
+ .. grid-item-card:: I/O API
+ :link: ../reference/api
+ :link-type: doc
+
+ Readers, writers, formats and trajectory objects for Python workflows.
+
+Analysis configuration
+----------------------
+
+RDF, MSD, VACF and vibrational calculations use key-value input files. Lists
+may be written in brackets or as multiline values according to the
+:ref:`inputFile` grammar. Relative filenames are resolved by the process
+running the command, so reproducible workflows should execute from a known run
+directory.
+
+Trajectories and engines
+------------------------
+
+Analysis commands default to PQ conventions. Use ``--engine`` when reading a
+supported alternative convention. Position analyses require coordinates and a
+consistent atom count; MSD additionally needs periodic cells for unwrapping.
+VACF and momentum analyses require velocity data. Molecular exclusions in RDF
+require topology information from a restart and moldescriptor.
+
+The Python format definitions are documented by
+:class:`PQAnalysis.traj.formats.MDEngineFormat` and
+:class:`PQAnalysis.traj.formats.TrajectoryFormat`.
+
+Selections
+----------
+
+Analysis selections are parsed by :class:`PQAnalysis.topology.selection.Selection`.
+Use elemental or atom-name selections for simple systems and full atom
+information when residue-aware selection is required. Always verify that the
+selection contains the intended atoms; normalization and statistical quality
+depend directly on its population.
+
+Output and conversion
+---------------------
+
+Native, CSV, TSV and PQAnalysis-generated XVG tables are mutually convertible.
+The converter detects input content rather than trusting the extension and can
+write several outputs atomically:
+
+.. code-block:: console
+
+ $ pqanalysis convert rdf.xvg \
+ -o rdf.dat \
+ -o rdf.csv \
+ -o rdf.tsv
+
+No output is written if any requested destination already exists. Use
+``--mode o`` only when intentional replacement is acceptable.
+
+.. toctree::
+ :hidden:
+ :maxdepth: 1
+
+ Analysis input files <../userGuide/inputFile>
+ Analysis output files <../userGuide/analysisOutputFiles>
diff --git a/docs/source/developerGuide/developerGuide.rst b/docs/source/developerGuide/developerGuide.rst
index cb29d6ba..3c713511 100644
--- a/docs/source/developerGuide/developerGuide.rst
+++ b/docs/source/developerGuide/developerGuide.rst
@@ -1,117 +1,107 @@
.. _developerGuide:
-###############
-Developer Guide
-###############
+Development
+===========
-This section includes information for developers who want to contribute to the project. It includes information about the project structure, how to run the tests, and how to build the documentation. It also includes information about the project's coding style and how to contribute to the project.
+PQAnalysis uses a ``dev`` integration branch and releases from ``main``.
+Feature and fix pull requests normally target ``dev``; release pull requests
+merge ``dev`` into ``main``.
-*****************
-Coding Guidelines
-*****************
+Local setup
+-----------
-The project follows the `PEP8 `_ coding style. The project uses `setuptools `_ for packaging and distribution. The project uses `Sphinx `_ for documentation. The project uses `pytest `_ for testing. The project uses `Gitflow `_ for branching.
+Clone the repository and install editable development, test and documentation
+dependencies:
-In order to contribute to the project, it is important to follow the coding style and guidelines used by the project, therefore please read ALL of the following sections carefully.
+.. code-block:: console
-*****************
-How to Contribute
-*****************
+ $ git clone https://github.com/MolarVerse/PQAnalysis.git
+ $ cd PQAnalysis
+ $ python -m venv .venv
+ $ source .venv/bin/activate
+ $ python -m pip install -e ".[dev,test,docs]"
-For any contributor willing to contribute to the project, it is important to understand the branching model used by the project. The project uses the `Gitflow `_ branching model. Pull requests should stay small and reviewer-readable. In order to contribute to the project please follow the following steps:
+Keep changes focused and add tests at the same ownership boundary as the
+behavior being changed.
+Tests
+-----
- #. Fork the project on Github. (not necessary if you are a member of the project)
+The full test script runs the suite with runtime type checking enabled and
+again with release settings:
- #. Clone your fork locally:
-
- .. code:: bash
+.. code-block:: console
- $ git clone https://github.com/MolarVerse/PQAnalysis.git
+ $ bash pytest.sh
- #. Initialize git flow with the following settings (if not specified default settings are used)
+For a focused iteration, pass ordinary pytest arguments:
- .. code:: bash
+.. code-block:: console
- [master] main
- [develop] dev
- [version tag prefix] v
+ $ bash pytest.sh tests/analysis/rdf -q
- #. Create a feature branch for your contribution:
-
- .. code:: bash
-
- $ git flow feature start
-
-
- #. Commit your changes to your feature branch and publish your feature branch:
-
- .. code:: bash
-
- $ git add
- $ git commit -m "fix: describe the bug fix"
- $ git flow feature publish
-
- #. Create a pull request on Github.
-
- #. Use a short Conventional Commits title for the pull request, for example ``feat: add a new analysis command`` or ``fix(io): handle missing trajectory data``. This title is validated by CI.
-
- #. Once your pull request is approved and all required checks pass, it will be merged into the develop branch. If the pull request is squash merged, use the pull request title as the squash commit message.
-
- #. Optional: enable the local commit-message hook for earlier feedback:
-
- .. code:: bash
-
- $ git config core.hooksPath .githooks
-
-*************
Documentation
-*************
-
-Please make sure that all code is well documented. The project uses `Sphinx `_ for documentation. The documentation of this webpage is autogenerated from the docstrings of the implemented code, thus it is important to make sure that all docstrings are correct and informative.
-
-.. attention::
-
- The project uses `numpydoc `_ for docstring formatting. Please make sure that all docstrings are formatted correctly.
+-------------
-In order to install all the dependencies required for building the documentation, use the following command:
+Build the complete documentation with warnings treated as errors:
-.. code:: bash
+.. code-block:: console
- $ pip install -e ".[docs]" # install the project with the documentation dependencies
+ $ python -m sphinx -W --keep-going \
+ -b html docs/source docs/build/html
-To build the documentation, use the following command:
+Check internal and external links separately:
-.. code:: bash
+.. code-block:: console
- $ cd docs
+ $ python -m sphinx -W --keep-going \
+ -b linkcheck docs/source docs/build/linkcheck
- $ make html
+The API reference is generated from package modules when Sphinx starts. Do not
+hand-edit generated files under ``docs/source/code`` unless the generator or
+its templates are being changed. User-facing scientific conventions belong in
+the curated analysis, data and reference pages.
-In order to view the documentation, open the following file in a web browser:
+Documentation structure
+-----------------------
-.. code:: bash
+* ``getting-started.rst`` provides the shortest working path.
+* ``analyses/`` explains physical definitions, inputs and interpretation.
+* ``data/`` covers file grammar, trajectories, selections and conversion.
+* ``reference/`` indexes CLI and Python interfaces.
+* ``userGuide/analysisOutputFiles.rst`` is the canonical output-schema source.
+* ``code/`` is generated API material.
- $ open build/html/index.html
+Every analysis guide should state the physical quantity, assumptions, units,
+minimal input, output fields and interpretation limits. Keep duplicated option
+tables in generated API documentation rather than copying them into several
+manual pages.
-For the CI/CD pipeline, the a documentation coverage of 99.9% is required. Please make sure that all implemented features are correctly documented. To evaluate the documentation coverage, use the following command:
+Pull requests
+-------------
-.. code:: bash
+Pull requests should be reviewer-readable and use a Conventional Commits title,
+for example ``feat: add a new analysis command`` or
+``fix(io): handle missing trajectory data``. The repository validates the PR
+title and uses it as the squash-merge commit message.
- $ docstr-coverage PQAnalysis
+The optional local commit-message hook provides earlier feedback:
-*******
-Testing
-*******
+.. code-block:: console
-The project uses `pytest `_ for testing. Before creating a pull request, please make sure that all tests pass and ensure a high quality of code coverage. In order to run the tests, use the following command:
+ $ git config core.hooksPath .githooks
-.. code:: bash
+Before requesting review, run the focused tests for the change and every
+relevant strict documentation build. CI publishes documentation only from
+``main``; pull requests and ``dev`` pushes build it without deploying.
- $ pip install -e ".[test]" # install the project with the test dependencies
+Docstrings
+----------
- $ python -m pytest
+Public Python interfaces use NumPy-style docstrings. Document parameters,
+returns, raised exceptions, units and array shapes precisely. Documentation
+coverage can be inspected with:
-The testing framework will run all tests and provide automatically generated coverage reports. Not only should all tests pass, but the coverage should be as close to 100% as possible. Furthermore, the project automatically uses doctest, so please make sure that all examples included in the doc strings of the implemented features are correct otherwise the tests will fail.
+.. code-block:: console
-Last, if any additional dependencies are required for testing, please add them to the ``pyproject.toml`` file under the ``[project.optional-dependencies]`` section.
+ $ docstr-coverage PQAnalysis
diff --git a/docs/source/getting-started.rst b/docs/source/getting-started.rst
new file mode 100644
index 00000000..db13da67
--- /dev/null
+++ b/docs/source/getting-started.rst
@@ -0,0 +1,99 @@
+Getting Started
+===============
+
+Install PQAnalysis
+------------------
+
+PQAnalysis supports Python 3.12 and newer. Install the current release from
+PyPI:
+
+.. code-block:: console
+
+ $ python -m pip install pqanalysis
+
+Confirm that the command dispatcher and analysis commands are available:
+
+.. code-block:: console
+
+ $ pqanalysis --help
+ $ pqanalysis rdf --help
+
+Run a first analysis
+--------------------
+
+Create ``rdf.in`` beside a PQ trajectory named ``trajectory.xyz``:
+
+.. code-block:: text
+
+ traj_files = trajectory.xyz
+ reference_selection = O
+ target_selection = H
+ delta_r = 0.05
+ out_file = rdf.dat
+
+Run the calculation:
+
+.. code-block:: console
+
+ $ pqanalysis rdf rdf.in
+
+``rdf.dat`` contains the bin-center distance, radial distribution function,
+cumulative coordination number, density-normalized shell population and
+ideal-gas pair-count residual. Its commented metadata header records the field
+names, scientific symbols and units. See :ref:`analysis-output-rdf` for the
+exact definitions.
+
+Choose output formats
+---------------------
+
+The output filename selects the table format. ``.csv`` and ``.tsv`` open
+directly in spreadsheet software, ``.xvg`` opens in xmgrace, and any other
+extension uses native PQAnalysis text.
+
+Additional outputs do not require another analysis run:
+
+.. code-block:: console
+
+ $ pqanalysis rdf rdf.in \
+ --export rdf.csv \
+ --export rdf.tsv \
+ --export rdf.xvg
+
+Existing analysis tables can be converted later:
+
+.. code-block:: console
+
+ $ pqanalysis convert rdf.dat -o rdf.csv -o rdf.xvg
+
+PQAnalysis refuses to overwrite an existing output unless replacement is
+requested explicitly with ``--mode o``.
+
+Next steps
+----------
+
+.. grid:: 1 2 2 2
+ :gutter: 2
+
+ .. grid-item-card:: Select an analysis
+ :link: analyses/index
+ :link-type: doc
+
+ Compare structural, transport, spectral and diagnostic calculations.
+
+ .. grid-item-card:: Input and data
+ :link: data/index
+ :link-type: doc
+
+ Learn the input grammar, trajectory conventions and output formats.
+
+ .. grid-item-card:: Command reference
+ :link: reference/cli
+ :link-type: doc
+
+ Inspect every command, positional argument and optional flag.
+
+ .. grid-item-card:: Python API
+ :link: reference/api
+ :link-type: doc
+
+ Integrate analyses and readers into Python workflows.
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 1580bbe1..dee90b6c 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -1,23 +1,98 @@
-.. PQAnalysis documentation master file, created by
- sphinx-quickstart on Mon Oct 23 16:52:21 2023.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-##########
PQAnalysis
-##########
+==========
-.. toctree::
- :hidden:
- :maxdepth: -1
-
- userGuide/userGuide
- developerGuide/developerGuide
- code/PQAnalysis.rst
+PQAnalysis provides command-line and Python tools for quantitative analysis of
+PQ molecular-dynamics simulations. It reads structures, trajectories,
+velocities and Hessians, then produces documented scientific tables for
+structural, transport and vibrational observables.
+
+:doc:`Get started ` | :doc:`Choose an analysis ` |
+:doc:`Work with data ` | :doc:`Command reference `
+
+Quick start
+-----------
+
+PQAnalysis requires Python 3.12 or newer.
+
+.. code-block:: console
+
+ $ python -m pip install pqanalysis
+ $ pqanalysis rdf rdf.in
+
+The output filename in an analysis input file selects native text, CSV, TSV or
+XVG. Repeat ``--export`` to write several formats in the same run.
+
+.. code-block:: console
+
+ $ pqanalysis rdf rdf.in --export rdf.csv --export rdf.xvg
+
+Documentation
+-------------
+
+.. grid:: 1 2 3 3
+ :gutter: 2
+
+ .. grid-item-card:: Getting started
+ :link: getting-started
+ :link-type: doc
+
+ Install PQAnalysis and run a first radial-distribution calculation.
+
+ .. grid-item-card:: Analyses
+ :link: analyses/index
+ :link-type: doc
-Welcome to PQAnalysis's documentation!
-======================================
+ RDF, MSD, VACF, spectra, normal modes and momentum diagnostics.
-:ref:`userGuide`
+ .. grid-item-card:: Data and conversion
+ :link: data/index
+ :link-type: doc
+
+ Input syntax, trajectories, selections and scientific table formats.
+
+ .. grid-item-card:: Command line
+ :link: reference/cli
+ :link-type: doc
+
+ Analysis, conversion and trajectory command reference.
+
+ .. grid-item-card:: Python API
+ :link: reference/api
+ :link-type: doc
+
+ Curated entry points and the complete generated package reference.
+
+ .. grid-item-card:: Development
+ :link: developerGuide/developerGuide
+ :link-type: doc
+
+ Branching, tests, documentation checks and contribution conventions.
+
+Scientific output
+-----------------
+
+Native analysis tables retain their established numeric layout and add a
+compact UTF-8 metadata header. Stable ASCII field names support scripts while
+Unicode symbols and units describe the physical quantities.
+
+.. code-block:: text
+
+ # PQAnalysis: Radial distribution function
+ # FIELDS r_i g_r_i N_r_i g_r_i_dV_i H_i_minus_E_i
+ # SYMBOLS rᵢ g(rᵢ) N(rᵢ) g(rᵢ)ΔVᵢ Hᵢ−Eᵢ
+ # UNITS Š1 1 ų pairs
+ 0.5 0.0 0.0 0.0 -0.05026548245743666
+
+See :ref:`analysisOutputFiles` for every column, normalization convention and
+conversion path.
+
+.. toctree::
+ :hidden:
+ :maxdepth: 2
+ :caption: Documentation
-:ref:`developerGuide`
+ getting-started
+ analyses/index
+ data/index
+ reference/index
+ Development
diff --git a/docs/source/reference/api.rst b/docs/source/reference/api.rst
new file mode 100644
index 00000000..71ca3973
--- /dev/null
+++ b/docs/source/reference/api.rst
@@ -0,0 +1,67 @@
+Python API
+==========
+
+The public analysis wrappers accept the same input files as the command line
+and are the simplest integration points:
+
+.. list-table:: Analysis entry points
+ :header-rows: 1
+ :widths: 34 66
+
+ * - Function
+ - Purpose
+ * - :func:`PQAnalysis.analysis.rdf.api.rdf`
+ - Radial distribution analysis
+ * - :func:`PQAnalysis.analysis.msd.api.msd`
+ - Mean square displacement analysis
+ * - :func:`PQAnalysis.analysis.vacf.api.vacf`
+ - Velocity or charge-flux correlation analysis
+ * - :func:`PQAnalysis.analysis.vibrational.api.vibrations`
+ - Vibrational analysis from a structure and Hessian
+ * - :func:`PQAnalysis.analysis.momentum.api.check_momentum`
+ - Frame-resolved total linear momentum
+
+Package areas
+-------------
+
+.. grid:: 1 2 3 3
+ :gutter: 2
+
+ .. grid-item-card:: Analysis API
+ :link: ../code/PQAnalysis.analysis
+ :link-type: doc
+
+ Calculations, input readers, result models and output writers.
+
+ .. grid-item-card:: Input and output
+ :link: ../code/PQAnalysis.io
+ :link-type: doc
+
+ Trajectory, restart, topology and simulation-file readers and writers.
+
+ .. grid-item-card:: Trajectories
+ :link: ../code/PQAnalysis.traj
+ :link-type: doc
+
+ Engine formats, trajectory containers and high-level operations.
+
+ .. grid-item-card:: Atomic systems
+ :link: ../code/PQAnalysis.atomic_system
+ :link-type: doc
+
+ Atomic coordinates, cells and topology-bearing systems.
+
+ .. grid-item-card:: Topology and selection
+ :link: ../code/PQAnalysis.topology
+ :link-type: doc
+
+ Selections, residues, bonded topology and SHAKE definitions.
+
+ .. grid-item-card:: Complete package index
+ :link: ../code/PQAnalysis
+ :link-type: doc
+
+ Every generated module, class, function and exception.
+
+Use the curated analysis guides for physical conventions and the generated
+reference for signatures and implementation-level details.
diff --git a/docs/source/reference/cli.rst b/docs/source/reference/cli.rst
new file mode 100644
index 00000000..5fa0688d
--- /dev/null
+++ b/docs/source/reference/cli.rst
@@ -0,0 +1,96 @@
+Command-Line Reference
+======================
+
+``pqanalysis`` dispatches all supported commands from one executable. Every
+subcommand also provides local help:
+
+.. code-block:: console
+
+ $ pqanalysis --help
+ $ pqanalysis rdf --help
+
+Analysis commands
+-----------------
+
+.. list-table:: Analysis commands
+ :class: pq-command-table
+ :header-rows: 1
+ :widths: 24 50 26
+
+ * - Command
+ - Purpose
+ - Primary input
+ * - :ref:`rdf `
+ - Radial distribution and cumulative coordination
+ - Input file
+ * - :ref:`msd `
+ - Mean square displacement and diffusion fits
+ - Input file
+ * - :ref:`vacf `
+ - Velocity or charge-flux correlation and spectra
+ - Input file
+ * - :ref:`vibrations `
+ - Hessian normal modes and optional IR intensities
+ - Input file
+ * - :ref:`check_momentum `
+ - Total linear momentum per velocity frame
+ - Trajectory files
+ * - :ref:`build_spectrum `
+ - Gaussian or Lorentzian broadening of discrete lines
+ - Line table
+
+Analysis commands accept ``--export FILE`` where applicable. Repeat the option
+to produce several output formats without repeating the calculation.
+
+Table conversion
+----------------
+
+``pqanalysis convert`` reads native, CSV, TSV or PQAnalysis-generated XVG
+analysis tables and writes one or more target formats. It preserves complete
+schemas and hidden XVG data sets. See
+:doc:`the generated option reference <../code/PQAnalysis.cli.convert>`.
+
+Structure and trajectory conversion
+-----------------------------------
+
+.. list-table:: Structure and trajectory commands
+ :class: pq-command-table
+ :header-rows: 1
+ :widths: 28 72
+
+ * - Command
+ - Purpose
+ * - :ref:`rst2xyz `
+ - Convert a PQ restart structure to XYZ
+ * - :ref:`xyz2rst `
+ - Convert XYZ coordinates to a PQ restart structure
+ * - :ref:`xyz2gen `
+ - Convert XYZ to DFTB+ GEN
+ * - :ref:`gen2xyz `
+ - Convert DFTB+ GEN to XYZ
+ * - :ref:`traj2box `
+ - Extract periodic box data from trajectories
+ * - :ref:`traj2extxyz `
+ - Write extended XYZ trajectories with selected metadata
+ * - :ref:`traj2qmcfc `
+ - Convert trajectories to QMCFC conventions
+
+Simulation-support commands
+---------------------------
+
+.. list-table:: Simulation-support commands
+ :class: pq-command-table
+ :header-rows: 1
+ :widths: 28 72
+
+ * - Command
+ - Purpose
+ * - :ref:`continue_input `
+ - Continue indexed PQ or QMCFC input/output sequences
+ * - :ref:`add_molecules `
+ - Add molecular structures to an existing system
+ * - :ref:`build_nep_traj `
+ - Assemble a trajectory from nudged-elastic-band data
+
+Commands refuse unsafe output replacement by default. Consult each generated
+reference page for its supported writing modes and format-specific options.
diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst
new file mode 100644
index 00000000..239dd118
--- /dev/null
+++ b/docs/source/reference/index.rst
@@ -0,0 +1,34 @@
+Reference
+=========
+
+Use the command reference for shell workflows and the Python API reference for
+library integration. Scientific output definitions remain centralized so CLI
+and API users share the same field names, units and normalization conventions.
+
+.. grid:: 1 2 3 3
+ :gutter: 2
+
+ .. grid-item-card:: Command line
+ :link: cli
+ :link-type: doc
+
+ Analysis, format-conversion and simulation-support commands.
+
+ .. grid-item-card:: Python API
+ :link: api
+ :link-type: doc
+
+ Curated public entry points and the complete package reference.
+
+ .. grid-item-card:: Output schemas
+ :link: ../userGuide/analysisOutputFiles
+ :link-type: doc
+
+ Stable fields, symbols, units and file-format behavior.
+
+.. toctree::
+ :hidden:
+ :maxdepth: 1
+
+ cli
+ api
diff --git a/docs/source/userGuide/analysisOutputFiles.rst b/docs/source/userGuide/analysisOutputFiles.rst
index 076f00eb..4112a05e 100644
--- a/docs/source/userGuide/analysisOutputFiles.rst
+++ b/docs/source/userGuide/analysisOutputFiles.rst
@@ -1,8 +1,7 @@
.. _analysisOutputFiles:
-#####################
Analysis Output Files
-#####################
+=====================
PQAnalysis analysis commands can write native text, CSV, TSV or XVG tables. The
output filename selects the format:
@@ -27,7 +26,7 @@ output filename selects the format:
- Native PQAnalysis text
- Self-describing scientific data and legacy workflows
-This means that ``out_file table.csv`` in an RDF, MSD, VACF or vibrations input
+This means that ``out_file = table.csv`` in an RDF, MSD, VACF or vibrations input
file writes CSV directly. Names ending in ``.dat``, ``.out``, ``.txt`` or no
extension retain the native format.
diff --git a/docs/source/userGuide/inputFile.rst b/docs/source/userGuide/inputFile.rst
index 3ea461cc..164f8525 100644
--- a/docs/source/userGuide/inputFile.rst
+++ b/docs/source/userGuide/inputFile.rst
@@ -1,50 +1,125 @@
.. _inputFile:
-##########
-Input File
-##########
+Analysis Input Files
+====================
-The general parsing of the input file is based on a Lark grammar implementation (For more details see `Lark Grammar `_). Any input file must be based on the following definitions of input key and value pairs:
+RDF, MSD, VACF and vibrational analyses use a compact key-value format parsed
+with `Lark `_. Each analysis documents its
+required and optional keys in the generated command and input-reader reference.
-.. note::
- There are two different types of input key and value pairs. The first type is the key and value pairs that are defined in line seperated by a :code:`=` e.g:
+Inline statements
+-----------------
- .. code-block:: bash
-
- key = value
+An inline statement assigns one value to one key:
- The second type are so called multiline statements where in the first line the key is defined and in the following lines the values assigned to the key. The multiline statements must be closed by an :code:`END` statement. The following example shows a multiline statement:
+.. code-block:: text
- .. code-block:: bash
+ key = value
- key
- value1
- value2
- END
+Several assignments may share a line when separated by commas:
- It is important to note that multiline statements are always parsed as list/array like values. This means, if the documentation of the key states that the value is not a list or array, an inlined statement must be used.
+.. code-block:: text
-.. note::
- In general, all keys are case-insensitive as well as the closing statement :code:`END` of a multiline statement. The values are case-sensitive. Furthermore, all keys and values are stripped from leading and trailing whitespaces and :code:`#` can be used to include comments (including inline comments). Inline statements using :code:`key = value` can also be used multiple times in one line separated by a :code:`,` to define multiple key and value pairs in one line e.g.:
+ window = 1000, gap = 10, time_step = 0.001
- .. code-block:: bash
+Use separate lines for scientific input files unless a compact generated file
+is required; one assignment per line is easier to review and diff.
- key1 = value1, key2 = value2
+Multiline lists
+---------------
-.. note::
- The values are read as strings and are converted to the correct type based on the documentation of the key (if possible). In general, the user should not worry about the type of the value as the parser will try to convert the value to the correct type. If the conversion fails, an error will be raised. The following examples show the conversion of the values:
+A key followed by values on subsequent lines creates a list. Terminate the
+list with ``END``:
- * :code:`True` and :code:`False` are converted to :code:`bool` (case-insensitive)
- * :code:`1` is converted to :code:`int` following possible conversions to :code:`float`
- * :code:`1.0` is converted to :code:`float`
- * :code:`any-kind-of_string` is converted to :code:`str`
- * :code:`[1, 2, 3]` is converted to :code:`list` following possible (all values have to be of the same type)
- * :code:`1..4` is converted to :code:`range` range(1, 4)
- * :code:`1-4` same as :code:`1..4`
- * :code:`1..3..10` is converted to :code:`range` range(1, 10, 3), please note that the step size is always the middle value in contrast to the python syntax
- * :code:`1-3-10` same as :code:`1..3..10`
- * :code:`file_0*.text` is treated as a list of files matching the pattern (For more details see the `glob package `_)
+.. code-block:: text
+ traj_files
+ trajectory-001.xyz
+ trajectory-002.xyz
+ trajectory-003.xyz
+ END
+Multiline syntax always produces a list-like value. Use inline syntax for keys
+that accept only a scalar.
+Comments and case
+-----------------
+Keys are case-insensitive. The closing ``END`` token must be uppercase. Values
+remain case-sensitive because they may contain filenames or selection
+expressions. Leading and trailing whitespace is ignored. ``#`` starts a
+comment, including at the end of a statement:
+
+.. code-block:: text
+
+ target_selection = O # oxygen atoms
+
+Value conversion
+----------------
+
+The parser converts strings to the type required by each documented key.
+Common forms include:
+
+.. list-table:: Input value forms
+ :header-rows: 1
+ :widths: 30 30 40
+
+ * - Input
+ - Parsed form
+ - Notes
+ * - ``True`` or ``False``
+ - Boolean
+ - Case-insensitive
+ * - ``1``
+ - Integer
+ - May also satisfy a real-valued key
+ * - ``1.0``
+ - Floating-point number
+ - Scientific notation is accepted where numeric keys permit it
+ * - ``[1, 2, 3]``
+ - List
+ - Elements must have compatible types
+ * - ``1..4`` or ``1-4``
+ - ``range(1, 4)``
+ - The stop value follows Python's exclusive convention
+ * - ``1..3..10`` or ``1-3-10``
+ - ``range(1, 10, 3)``
+ - The middle value is the step
+ * - ``frame-*.xyz``
+ - Matching file list
+ - Expanded with Python glob semantics
+
+Filenames
+---------
+
+Relative filenames are interpreted from the command's working directory. The
+ordinary filename grammar accepts letters, digits, ``_``, ``-`` and ``.``;
+``*`` provides glob matching. For a portable analysis directory, keep the
+input file and its referenced data together and run the command from that
+directory.
+
+Complete example
+----------------
+
+.. code-block:: text
+
+ # oxygen-hydrogen radial distribution
+ traj_files
+ run-001.xyz
+ run-002.xyz
+ END
+
+ reference_selection = O
+ target_selection = H
+ delta_r = 0.05
+ r_max = 8.0
+ out_file = rdf.dat
+
+Run it with:
+
+.. code-block:: console
+
+ $ pqanalysis rdf rdf.in
+
+See :doc:`../analyses/index` for analysis-specific examples and
+:doc:`analysisOutputFiles` for output formats and scientific schemas.
diff --git a/docs/source/userGuide/userGuide.rst b/docs/source/userGuide/userGuide.rst
index 8e90e4ca..b40c8280 100644
--- a/docs/source/userGuide/userGuide.rst
+++ b/docs/source/userGuide/userGuide.rst
@@ -1,160 +1,35 @@
+:orphan:
+
.. _userGuide:
-##########
User Guide
-##########
-
-.. toctree::
- :hidden:
- :maxdepth: 1
-
- inputFile
- analysisOutputFiles
-
-Command Line Interface
-======================
-
-The PQAnalysis package does not only provide an API but also a number of different command line tools. These tools can be categorized into two groups primary groups: pure command line tools and tools that are based on an input file.
-
-Input file based tools
-----------------------
-
-For more details on the grammar and syntax of the input file see :ref:`inputFile`.
-For the columns, units and normalization conventions of analysis output files,
-see :ref:`analysisOutputFiles`.
-
-- :ref:`rdf`
-- :ref:`msd`
-- :ref:`vacf`
-- :ref:`vibrations`
-
-RDF input files
-^^^^^^^^^^^^^^^
-
-Basic RDF calculations only need a trajectory, selections, bin settings,
-and an output file. A restart file is not required for this case:
-
-.. code-block:: text
-
- reference_selection = H
- target_selection = O
- delta_r = 0.05
- out_file = rdf.out
- traj_files = trajectory.xyz
-
-Restart files and moldescriptor files are only needed when the calculation
-requires molecular topology information. For example,
-:code:`no_intra_molecular = True` excludes pairs from the same molecule.
-If the files are not given explicitly, PQAnalysis tries to infer
-:code:`trajectory.rst` from :code:`trajectory.xyz` and
-:code:`moldescriptor.dat` from the trajectory directory:
-
-.. code-block:: text
-
- reference_selection = H
- target_selection = O
- delta_r = 0.05
- out_file = rdf_inter.out
- traj_files = trajectory.xyz
- no_intra_molecular = True
-
-Explicit :code:`restart_file` and :code:`moldescriptor_file` values are used
-as-is. If both files are given and :code:`no_intra_molecular` is omitted,
-:code:`no_intra_molecular` defaults to :code:`True`. If
-:code:`no_intra_molecular` is set to :code:`False`, intra molecular pairs are
-included. Inferred and defaulted values are written to the normal PQAnalysis
-log output.
-
-Vibrational analysis input files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Vibrational analyses use a structure file and a Cartesian Hessian matrix. The Hessian can be generated by a PQ ``mm-hessian`` run.
-
-.. code-block:: text
-
- structure_file = structure.rst
- hessian_file = hessian.dat
- moldescriptor_file = moldescriptor.dat
- out_file = wavenumbers.dat
- normal_modes_file = normal_modes.dat
- modes_prefix = mode
- modes_file = modes.xyz
- modes = positive
- modes_frames = 30
- modes_amplitude = 0.25
- modes_threshold = 1.0e-6
- unit = kcal
- hessian_sign = auto
-
-The ``moldescriptor_file`` key is optional, but IR intensities require partial charges. ``unit`` accepts ``kcal``, ``hartree`` and ``ev``. ``hessian_sign = auto`` lets PQAnalysis choose the sign convention that gives the larger number of non-negative vibrational modes.
-
-Mode visualization is optional. ``modes_prefix`` writes one sinusoidal multi-frame XYZ animation per selected mode, for example ``mode-6.xyz``. ``modes_file`` writes one extended XYZ file with mode vectors and metadata, similar to ASE/Jmol vibration output. ``modes`` accepts ``all``, ``nonzero``, ``positive``, one mode number, a list of mode numbers or a range. Explicit mode numbers are one-based. ``modes_frames`` controls animation frames, ``modes_amplitude`` controls fixed-amplitude displacement in Angstrom, and ``modes_threshold`` filters named mode selections in ``cm-1``. ``modes_temperature`` can be used instead for ASE-style energy-scaled animations.
-
-MSD input files
-^^^^^^^^^^^^^^^
-
-Mean square displacement analyses compute the multiple-time-origin MSD of a
-selected atom set with periodic-image unwrapping. If ``time_step`` (in ps) is
-given, the self-diffusion coefficient is obtained from an Einstein-relation
-fit over the trailing ``fit_window`` points and reported in the log output in
-m\ :sup:`2`/s:
-
-.. code-block:: text
+==========
- traj_files = trajectory.xyz
- target_selection = O
- out_file = msd.dat
- window = 1000
- gap = 10
- time_step = 0.001
- fit_window = 200
+The PQAnalysis user documentation is organized by task:
-The output file contains the frame lag and the per-axis MSD in Angstrom
-squared, matching the format of the legacy Diffcalc tool. ``window`` must be
-divisible by ``gap``.
+.. grid:: 1 2 2 2
+ :gutter: 2
-VACF input files
-^^^^^^^^^^^^^^^^
+ .. grid-item-card:: Getting started
+ :link: ../getting-started
+ :link-type: doc
-Velocity autocorrelation analyses read a velocity trajectory (``.vel``) and
-compute the normalized VACF; with ``spectrum_file`` set, the windowed cosine
-transform yields a vibrational power spectrum in cm\ :sup:`-1`:
+ Installation, first RDF calculation and output formats.
-.. code-block:: text
+ .. grid-item-card:: Analyses
+ :link: ../analyses/index
+ :link-type: doc
- traj_files = trajectory.vel
- target_selection = all
- out_file = vacf.dat
- time_step = 0.001
- window = 2500
- gap = 5
- spectrum_file = spectrum.dat
- ftsize = 5000
- window_function = exponential
- window_param = 4.0
- window_start = 0.0
- window_stop = 1.0
+ Scientific definitions, input examples and interpretation guidance.
-Setting ``charge_file`` (static charges) or ``charge_files`` (a charge
-trajectory read in lockstep) switches to the charge-flux autocorrelation
-q\ :sub:`i`\ v\ :sub:`i`, whose spectrum approximates an infrared spectrum.
-``window_function`` accepts ``exponential``, ``hann`` and ``blackman``;
-``method = fft`` selects a faster dense-origin estimator instead of the
-legacy-exact sliding-origin one.
+ .. grid-item-card:: Data and conversion
+ :link: ../data/index
+ :link-type: doc
-Pure command line tools
------------------------
+ Input grammar, trajectories, selections and scientific tables.
-- :ref:`build_spectrum`
-- :ref:`check_momentum`
-- :ref:`continue_input`
-- :ref:`rst2xyz`
-- :ref:`traj2extxyz`
-- :ref:`traj2qmcfc`
-- :ref:`traj2box`
+ .. grid-item-card:: Reference
+ :link: ../reference/index
+ :link-type: doc
-Note that :ref:`check_momentum` parses velocities in
-single precision: reported momentum norms below roughly 1e-7 times the
-scaled sum of m\ :sub:`i` \|v\ :sub:`i`\| are parsing noise rather than
-physical center of mass drift (the legacy ``equipartition.jl`` tool parses
-in double precision and resolves smaller drift).
+ Command-line options, Python APIs and output schemas.
diff --git a/pyproject.toml b/pyproject.toml
index 861260d0..4b9c2df8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -44,9 +44,11 @@ dev = [
"yapf",
]
docs = [
- "sphinx>=7,<9",
+ "furo>=2024.8.6,<2027",
+ "sphinx>=8,<9",
+ "sphinx-copybutton>=0.5,<1",
+ "sphinx-design>=0.6,<1",
"sphinx-sitemap",
- "sphinx-rtd-theme",
"breathe",
"myst-parser",
"better-apidoc",
@@ -95,4 +97,6 @@ gen2xyz = "PQAnalysis.cli.gen2xyz:main"
[project.urls]
"Homepage" = "https://github.com/MolarVerse/PQAnalysis"
+"Documentation" = "https://molarverse.github.io/PQAnalysis/"
+"Repository" = "https://github.com/MolarVerse/PQAnalysis"
"PQ" = "https://github.com/MolarVerse/PQ"
From 9ef5ecd9a16009eb9c1c0a0519ba96fd4b8e1973 Mon Sep 17 00:00:00 2001
From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com>
Date: Fri, 7 Aug 2026 12:33:36 +0200
Subject: [PATCH 2/7] docs: refine scientific presentation
---
docs/source/_plots/_style.py | 48 ++++++++++++
docs/source/_plots/msd.py | 50 +++++++++++++
docs/source/_plots/rdf.py | 73 +++++++++++++++++++
docs/source/_plots/vacf.py | 50 +++++++++++++
docs/source/_plots/vibrations.py | 73 +++++++++++++++++++
docs/source/_static/css/custom.css | 48 ++++++++++--
docs/source/_templates/package.rst | 2 +-
docs/source/analyses/index.rst | 43 +----------
docs/source/analyses/msd.rst | 10 +++
docs/source/analyses/rdf.rst | 9 +++
docs/source/analyses/vacf.rst | 9 +++
docs/source/analyses/vibrations.rst | 9 +++
docs/source/conf.py | 8 +-
docs/source/data/index.rst | 30 ++------
docs/source/developerGuide/developerGuide.rst | 7 +-
docs/source/getting-started.rst | 31 ++------
docs/source/index.rst | 70 +++++++-----------
docs/source/reference/api.rst | 60 +++++----------
docs/source/reference/index.rst | 24 +-----
docs/source/userGuide/userGuide.rst | 32 ++------
pyproject.toml | 2 +-
21 files changed, 457 insertions(+), 231 deletions(-)
create mode 100644 docs/source/_plots/_style.py
create mode 100644 docs/source/_plots/msd.py
create mode 100644 docs/source/_plots/rdf.py
create mode 100644 docs/source/_plots/vacf.py
create mode 100644 docs/source/_plots/vibrations.py
diff --git a/docs/source/_plots/_style.py b/docs/source/_plots/_style.py
new file mode 100644
index 00000000..6c2ebefe
--- /dev/null
+++ b/docs/source/_plots/_style.py
@@ -0,0 +1,48 @@
+"""Shared Matplotlib style for the scientific documentation figures."""
+
+from pathlib import Path
+
+import matplotlib as mpl
+
+
+PROJECT_ROOT = Path(__file__).resolve().parents[3]
+
+COLORS = {
+ "blue": "#176c8c",
+ "green": "#008f72",
+ "orange": "#c7521c",
+ "magenta": "#a84d84",
+ "ink": "#202428",
+ "muted": "#66717a",
+ "grid": "#d7dde1",
+ "shell": "#dcecf2",
+}
+
+
+def apply_style(figsize: tuple[float, float]) -> None:
+ """Apply a restrained, colorblind-safe style to one figure."""
+
+ mpl.rcParams.update({
+ "figure.figsize": figsize,
+ "figure.dpi": 120,
+ "figure.facecolor": "white",
+ "savefig.facecolor": "white",
+ "savefig.bbox": "tight",
+ "font.size": 9.5,
+ "axes.labelsize": 10,
+ "axes.labelcolor": COLORS["ink"],
+ "axes.edgecolor": COLORS["muted"],
+ "axes.linewidth": 0.8,
+ "axes.spines.top": False,
+ "axes.spines.right": False,
+ "axes.axisbelow": True,
+ "axes.grid": True,
+ "grid.color": COLORS["grid"],
+ "grid.linewidth": 0.7,
+ "grid.alpha": 0.8,
+ "xtick.color": COLORS["ink"],
+ "ytick.color": COLORS["ink"],
+ "legend.frameon": False,
+ "legend.fontsize": 8.5,
+ "lines.linewidth": 1.8,
+ })
diff --git a/docs/source/_plots/msd.py b/docs/source/_plots/msd.py
new file mode 100644
index 00000000..a03a7343
--- /dev/null
+++ b/docs/source/_plots/msd.py
@@ -0,0 +1,50 @@
+"""MSD components and diffusion-fit interval from the validation fixture."""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from _style import COLORS, PROJECT_ROOT, apply_style
+
+
+apply_style((7.2, 4.3))
+
+data = np.loadtxt(PROJECT_ROOT / "tests/data/msd/msd_ref_O.dat")
+time = data[:, 0] * 0.5
+components = data[:, 1:4]
+total = np.sum(components, axis=1)
+
+fit_start = len(time) - 20
+fit_coefficients = np.polyfit(time[fit_start:], total[fit_start:], 1)
+fit = np.polyval(fit_coefficients, time[fit_start:])
+
+figure, axis = plt.subplots()
+for values, label, color in zip(
+ components.T,
+ (r"$\mathrm{MSD}_x$", r"$\mathrm{MSD}_y$", r"$\mathrm{MSD}_z$"),
+ (COLORS["blue"], COLORS["green"], COLORS["magenta"]),
+):
+ axis.plot(time, values, color=color, linewidth=1.35, label=label)
+
+axis.plot(time, total, color=COLORS["ink"], linewidth=2.2, label="total")
+axis.axvspan(
+ time[fit_start],
+ time[-1],
+ color=COLORS["shell"],
+ label="fit interval",
+)
+axis.plot(
+ time[fit_start:],
+ fit,
+ color=COLORS["orange"],
+ linestyle="--",
+ linewidth=1.7,
+ label="linear fit",
+)
+axis.set_xlabel(r"Lag time $t$ / ps")
+axis.set_ylabel(r"Mean square displacement / $\mathrm{\AA}^2$")
+axis.set_xlim(time[0], time[-1])
+axis.set_ylim(bottom=0.0)
+axis.legend(ncol=3, loc="upper left")
+
+figure.tight_layout()
+plt.show()
diff --git a/docs/source/_plots/rdf.py b/docs/source/_plots/rdf.py
new file mode 100644
index 00000000..f9ce3dee
--- /dev/null
+++ b/docs/source/_plots/rdf.py
@@ -0,0 +1,73 @@
+"""Analytic RDF profile used to explain structural features."""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from _style import COLORS, apply_style
+
+
+apply_style((7.2, 5.0))
+
+r = np.linspace(0.02, 8.0, 800)
+excluded_volume = 1.0 - np.exp(-(r / 1.65)**8)
+structure = (
+ 1.0
+ + 2.2 * np.exp(-0.5 * ((r - 2.80) / 0.22)**2)
+ - 0.55 * np.exp(-0.5 * ((r - 3.55) / 0.30)**2)
+ + 0.65 * np.exp(-0.5 * ((r - 4.65) / 0.38)**2)
+ - 0.18 * np.exp(-0.5 * ((r - 5.55) / 0.45)**2)
+)
+g_r = np.clip(excluded_volume * structure, 0.0, None)
+
+number_density = 0.0334
+coordination_integrand = 4.0 * np.pi * number_density * r**2 * g_r
+coordination = np.concatenate((
+ [0.0],
+ np.cumsum(
+ 0.5
+ * (coordination_integrand[1:] + coordination_integrand[:-1])
+ * np.diff(r)
+ ),
+))
+
+first_minimum = 3.55
+figure, (rdf_axis, coordination_axis) = plt.subplots(
+ 2,
+ 1,
+ sharex=True,
+ gridspec_kw={"height_ratios": (2.0, 1.25)},
+)
+
+rdf_axis.axvspan(
+ 0.0,
+ first_minimum,
+ color=COLORS["shell"],
+ label="first coordination shell",
+)
+rdf_axis.plot(r, g_r, color=COLORS["blue"])
+rdf_axis.axhline(1.0, color=COLORS["muted"], linestyle=":", linewidth=1.1)
+rdf_axis.axvline(
+ first_minimum,
+ color=COLORS["orange"],
+ linestyle="--",
+ linewidth=1.2,
+ label="first minimum",
+)
+rdf_axis.set_ylabel(r"$g(r)$")
+rdf_axis.set_ylim(0.0, 3.6)
+rdf_axis.legend(loc="upper right")
+
+coordination_axis.plot(r, coordination, color=COLORS["orange"])
+coordination_axis.axvline(
+ first_minimum,
+ color=COLORS["orange"],
+ linestyle="--",
+ linewidth=1.2,
+)
+coordination_axis.set_xlabel(r"Distance $r$ / $\mathrm{\AA}$")
+coordination_axis.set_ylabel(r"$N(r)$")
+coordination_axis.set_xlim(0.0, 8.0)
+coordination_axis.set_ylim(bottom=0.0)
+
+figure.tight_layout()
+plt.show()
diff --git a/docs/source/_plots/vacf.py b/docs/source/_plots/vacf.py
new file mode 100644
index 00000000..80598b2e
--- /dev/null
+++ b/docs/source/_plots/vacf.py
@@ -0,0 +1,50 @@
+"""VACF and Hann-window spectrum from the validation fixture."""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from _style import COLORS, PROJECT_ROOT, apply_style
+
+
+apply_style((7.2, 5.1))
+
+correlation = np.loadtxt(PROJECT_ROOT / "tests/data/vacf/vacf_ref.dat")
+spectrum = np.loadtxt(
+ PROJECT_ROOT / "tests/data/vacf/spectrum_hann_ref.dat"
+)
+spectrum = spectrum[spectrum[:, 0] <= 4000.0]
+
+figure, (correlation_axis, spectrum_axis) = plt.subplots(
+ 2,
+ 1,
+ gridspec_kw={"height_ratios": (1.25, 1.0)},
+)
+
+correlation_axis.plot(
+ correlation[:, 0],
+ correlation[:, 1],
+ color=COLORS["blue"],
+)
+correlation_axis.axhline(
+ 0.0,
+ color=COLORS["muted"],
+ linestyle=":",
+ linewidth=1.0,
+)
+correlation_axis.set_xlabel(r"Lag time $t$ / ps")
+correlation_axis.set_ylabel(r"$C_v(t)$")
+correlation_axis.set_xlim(correlation[0, 0], correlation[-1, 0])
+correlation_axis.set_ylim(-1.05, 1.05)
+
+spectrum_axis.plot(
+ spectrum[:, 0],
+ spectrum[:, 1],
+ color=COLORS["orange"],
+)
+spectrum_axis.set_xlabel(r"Wavenumber $\tilde{\nu}$ / $\mathrm{cm}^{-1}$")
+spectrum_axis.set_ylabel("Amplitude / a.u.")
+spectrum_axis.set_xlim(0.0, 4000.0)
+spectrum_axis.set_ylim(bottom=0.0)
+
+figure.tight_layout()
+plt.show()
diff --git a/docs/source/_plots/vibrations.py b/docs/source/_plots/vibrations.py
new file mode 100644
index 00000000..7bb50df2
--- /dev/null
+++ b/docs/source/_plots/vibrations.py
@@ -0,0 +1,73 @@
+"""IR stick spectrum calculated from the H2O validation fixture."""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from PQAnalysis.analysis.vibrational.vibrational_analysis import (
+ calculate_from_system,
+ read_hessian_file,
+)
+from PQAnalysis.io import MoldescriptorReader, RestartFileReader
+
+from _style import COLORS, PROJECT_ROOT, apply_style
+
+
+apply_style((7.2, 3.8))
+
+fixture = PROJECT_ROOT / "tests/data/vibrational"
+moldescriptor = fixture / "moldescriptor.dat"
+system = RestartFileReader(
+ str(fixture / "h2o.rst"),
+ moldescriptor_filename=str(moldescriptor),
+).read()
+hessian = read_hessian_file(str(fixture / "hessian.dat"))
+charges = np.asarray(
+ MoldescriptorReader(str(moldescriptor)).read()[0].partial_charges,
+ dtype=float,
+)
+result = calculate_from_system(
+ system,
+ hessian,
+ atom_charges=charges,
+)
+
+internal_modes = result.wavenumbers > 100.0
+wavenumbers = result.wavenumbers[internal_modes]
+intensities = result.intensities[internal_modes]
+
+figure, axis = plt.subplots()
+axis.vlines(
+ wavenumbers,
+ 0.0,
+ intensities,
+ color=COLORS["blue"],
+ linewidth=2.0,
+)
+axis.scatter(
+ wavenumbers,
+ intensities,
+ color=COLORS["blue"],
+ marker="_",
+ s=85,
+)
+for index, (wavenumber, intensity) in enumerate(
+ zip(wavenumbers, intensities)
+):
+ axis.annotate(
+ f"{wavenumber:.0f}",
+ (wavenumber, intensity),
+ xytext=(0, 5 + 10 * (index % 2)),
+ textcoords="offset points",
+ ha="center",
+ va="bottom",
+ color=COLORS["ink"],
+ fontsize=8,
+ )
+
+axis.set_xlabel(r"Wavenumber $\tilde{\nu}$ / $\mathrm{cm}^{-1}$")
+axis.set_ylabel(r"IR intensity / $\mathrm{km\ mol}^{-1}$")
+axis.set_xlim(0.0, 4200.0)
+axis.set_ylim(0.0, max(intensities) * 1.22)
+
+figure.tight_layout()
+plt.show()
diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css
index a7e33447..affc1368 100644
--- a/docs/source/_static/css/custom.css
+++ b/docs/source/_static/css/custom.css
@@ -1,21 +1,57 @@
+:root {
+ --pq-plot-background: #fff;
+}
+
+.sidebar-brand {
+ flex-direction: row;
+ align-items: center;
+ gap: 0.75rem;
+ padding-block: 0.75rem;
+}
+
+.sidebar-logo-container {
+ display: flex;
+ flex: 0 0 4.5rem;
+ align-items: center;
+ margin: 0;
+}
+
.sidebar-logo {
- width: 4rem;
+ width: 4.5rem;
+ margin: 0;
}
.sidebar-brand-text {
+ margin: 0;
+ font-size: 1.35rem;
font-weight: 700;
+ line-height: 1.1;
letter-spacing: 0;
}
-.sd-card {
- border-radius: 4px;
- box-shadow: none;
-}
-
code.literal {
border-radius: 2px;
}
+figure:has(> img.plot-directive) {
+ margin-block: 1.5rem 2rem;
+}
+
+img.plot-directive {
+ width: 100%;
+ height: auto;
+ border: 1px solid var(--color-foreground-border);
+ background: var(--pq-plot-background);
+}
+
+img.plot-directive + figcaption {
+ margin-top: 0.65rem;
+ color: var(--color-foreground-secondary);
+ font-size: 0.9rem;
+ line-height: 1.45;
+ text-align: left;
+}
+
.table-wrapper {
overflow-x: auto;
}
diff --git a/docs/source/_templates/package.rst b/docs/source/_templates/package.rst
index 195448b0..86c9a1c2 100644
--- a/docs/source/_templates/package.rst
+++ b/docs/source/_templates/package.rst
@@ -1,4 +1,4 @@
-{# Generated packages stay outside the curated user-facing navigation. #}
+{# Generated packages stay outside the maintained user-facing navigation. #}
:orphan:
:autogenerated:
diff --git a/docs/source/analyses/index.rst b/docs/source/analyses/index.rst
index b5e891c4..6837b88f 100644
--- a/docs/source/analyses/index.rst
+++ b/docs/source/analyses/index.rst
@@ -6,45 +6,6 @@ time-correlation spectra, molecular normal modes and conservation diagnostics.
Choose the observable from the physical question and from the data recorded by
the simulation.
-.. grid:: 1 2 3 3
- :gutter: 2
-
- .. grid-item-card:: Radial distribution
- :link: rdf
- :link-type: doc
-
- Pair structure, preferred separations and coordination numbers.
-
- .. grid-item-card:: Mean square displacement
- :link: msd
- :link-type: doc
-
- Translational motion and Einstein-relation diffusion estimates.
-
- .. grid-item-card:: VACF and spectra
- :link: vacf
- :link-type: doc
-
- Velocity or charge-flux correlation and frequency-domain spectra.
-
- .. grid-item-card:: Vibrational analysis
- :link: vibrations
- :link-type: doc
-
- Hessian normal modes, wavenumbers, force constants and IR intensities.
-
- .. grid-item-card:: Total momentum
- :link: momentum
- :link-type: doc
-
- Frame-resolved linear momentum and center-of-mass drift diagnostics.
-
- .. grid-item-card:: Output schemas
- :link: ../userGuide/analysisOutputFiles
- :link-type: doc
-
- Exact columns, units, normalizations and format conversion behavior.
-
Choose by input data
--------------------
@@ -71,6 +32,10 @@ Choose by input data
- Velocities and atomic masses
- :math:`|\sum_i m_i\mathbf{v}_i|` per frame
+The method pages define each estimator, its assumptions and its interpretation
+limits. File columns and units are specified once in
+:ref:`analysisOutputFiles`.
+
.. toctree::
:hidden:
:maxdepth: 1
diff --git a/docs/source/analyses/msd.rst b/docs/source/analyses/msd.rst
index 8698a806..f755db50 100644
--- a/docs/source/analyses/msd.rst
+++ b/docs/source/analyses/msd.rst
@@ -13,6 +13,16 @@ origins according to
Coordinates are unwrapped with the periodic cell before displacements are
accumulated.
+Estimator and fit interval
+--------------------------
+
+.. plot:: _plots/msd.py
+ :alt: Cartesian and total mean square displacement with a linear fit
+ :caption: Bundled oxygen-atom validation fixture with a 0.5 ps frame
+ interval. The dashed line fits the final 20 total-MSD samples and
+ illustrates fit-window selection; the fixture is not a material
+ diffusion benchmark.
+
Minimal input
-------------
diff --git a/docs/source/analyses/rdf.rst b/docs/source/analyses/rdf.rst
index 63809510..e99596fc 100644
--- a/docs/source/analyses/rdf.rst
+++ b/docs/source/analyses/rdf.rst
@@ -14,6 +14,15 @@ where :math:`H_i` is the eligible pair count, :math:`\rho_T` the target number
density, :math:`N_R` the number of reference atoms, :math:`N_F` the number of
frames and :math:`\Delta V_i` the spherical-shell volume.
+Structural interpretation
+-------------------------
+
+.. plot:: _plots/rdf.py
+ :alt: Radial distribution function and cumulative coordination number
+ :caption: Analytic schematic, not simulation output. The shaded interval
+ ends at the first minimum. The lower panel evaluates
+ N(r) = 4πρ∫₀ʳ g(s)s² ds with ρ = 0.0334 Å⁻³.
+
Minimal input
-------------
diff --git a/docs/source/analyses/vacf.rst b/docs/source/analyses/vacf.rst
index b4284dd2..42bcb270 100644
--- a/docs/source/analyses/vacf.rst
+++ b/docs/source/analyses/vacf.rst
@@ -15,6 +15,15 @@ static or time-dependent partial charges are supplied, it correlates
:math:`q_i\mathbf{v}_i` instead, producing a charge-flux spectrum that
approximates an infrared spectrum.
+Correlation and spectrum
+------------------------
+
+.. plot:: _plots/vacf.py
+ :alt: Velocity autocorrelation function and its Hann-window spectrum
+ :caption: Bundled VACF validation fixture and its Hann-window cosine
+ transform. Spectrum amplitudes are reported in arbitrary units; the
+ displayed range is limited to 4000 cm⁻¹.
+
Minimal input
-------------
diff --git a/docs/source/analyses/vibrations.rst b/docs/source/analyses/vibrations.rst
index fb05df81..1421b705 100644
--- a/docs/source/analyses/vibrations.rst
+++ b/docs/source/analyses/vibrations.rst
@@ -6,6 +6,15 @@ eigenvectors define normal modes and its eigenvalues determine signed
wavenumbers. Negative wavenumbers represent imaginary modes associated with
negative curvature of the potential-energy surface.
+Internal-mode spectrum
+----------------------
+
+.. plot:: _plots/vibrations.py
+ :alt: Infrared stick spectrum for the water validation fixture
+ :caption: IR stick spectrum calculated by PQAnalysis from the bundled H₂O
+ structure, Hessian and partial-charge fixtures. Only internal modes above
+ 100 cm⁻¹ are shown; translational and rotational modes are omitted.
+
Minimal input
-------------
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 94aa9ca8..cb0911fc 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -10,6 +10,7 @@
PROJECT_ROOT = DOCS_DIR.parent
sys.path.insert(0, str(PROJECT_ROOT))
+sys.path.insert(0, str(SOURCE_DIR / "_plots"))
project = "PQAnalysis"
author = "the PQAnalysis authors"
@@ -33,9 +34,9 @@
"sphinx.ext.autosummary",
"sphinx.ext.inheritance_diagram",
"sphinx_sitemap",
+ "matplotlib.sphinxext.plot_directive",
"myst_parser",
"sphinx_copybutton",
- "sphinx_design",
]
napoleon_google_docstring = True
@@ -60,6 +61,11 @@
copybutton_prompt_text = r">>> |\.\.\. |\$ "
copybutton_prompt_is_regexp = True
+plot_formats = [("svg", 96)]
+plot_html_show_formats = False
+plot_html_show_source_link = False
+plot_include_source = False
+
templates_path = ["_templates"]
source_suffix = {
".rst": "restructuredtext",
diff --git a/docs/source/data/index.rst b/docs/source/data/index.rst
index ad1e8fae..41df11aa 100644
--- a/docs/source/data/index.rst
+++ b/docs/source/data/index.rst
@@ -5,32 +5,12 @@ PQAnalysis separates simulation data, analysis configuration and output-table
serialization. File extensions select output formats, while input content and
explicit engine options determine how trajectories are read.
-.. grid:: 1 2 2 2
- :gutter: 2
+This section covers four interfaces:
- .. grid-item-card:: Analysis input files
- :link: ../userGuide/inputFile
- :link-type: doc
-
- Key-value grammar, scalar values, lists and comments.
-
- .. grid-item-card:: Output tables
- :link: ../userGuide/analysisOutputFiles
- :link-type: doc
-
- Native metadata, CSV, TSV, XVG, columns, units and normalization.
-
- .. grid-item-card:: Command-line conversion
- :link: ../reference/cli
- :link-type: doc
-
- Convert analysis tables, structures, trajectories and box data.
-
- .. grid-item-card:: I/O API
- :link: ../reference/api
- :link-type: doc
-
- Readers, writers, formats and trajectory objects for Python workflows.
+* :ref:`inputFile` defines the key-value grammar.
+* :ref:`analysisOutputFiles` defines table fields, symbols and units.
+* :doc:`../reference/cli` documents table, structure and trajectory conversion.
+* :doc:`../reference/api` identifies readers, writers and trajectory objects.
Analysis configuration
----------------------
diff --git a/docs/source/developerGuide/developerGuide.rst b/docs/source/developerGuide/developerGuide.rst
index 3c713511..13f1d547 100644
--- a/docs/source/developerGuide/developerGuide.rst
+++ b/docs/source/developerGuide/developerGuide.rst
@@ -60,13 +60,15 @@ Check internal and external links separately:
The API reference is generated from package modules when Sphinx starts. Do not
hand-edit generated files under ``docs/source/code`` unless the generator or
its templates are being changed. User-facing scientific conventions belong in
-the curated analysis, data and reference pages.
+the maintained analysis, data and reference pages.
Documentation structure
-----------------------
* ``getting-started.rst`` provides the shortest working path.
* ``analyses/`` explains physical definitions, inputs and interpretation.
+* ``_plots/`` contains executable Matplotlib figures built from documented
+ analytic models or versioned validation fixtures.
* ``data/`` covers file grammar, trajectories, selections and conversion.
* ``reference/`` indexes CLI and Python interfaces.
* ``userGuide/analysisOutputFiles.rst`` is the canonical output-schema source.
@@ -75,7 +77,8 @@ Documentation structure
Every analysis guide should state the physical quantity, assumptions, units,
minimal input, output fields and interpretation limits. Keep duplicated option
tables in generated API documentation rather than copying them into several
-manual pages.
+manual pages. Figure captions must identify their data source and distinguish
+analytic schematics, validation fixtures and physical benchmark results.
Pull requests
-------------
diff --git a/docs/source/getting-started.rst b/docs/source/getting-started.rst
index db13da67..be5ba7aa 100644
--- a/docs/source/getting-started.rst
+++ b/docs/source/getting-started.rst
@@ -71,29 +71,8 @@ requested explicitly with ``--mode o``.
Next steps
----------
-.. grid:: 1 2 2 2
- :gutter: 2
-
- .. grid-item-card:: Select an analysis
- :link: analyses/index
- :link-type: doc
-
- Compare structural, transport, spectral and diagnostic calculations.
-
- .. grid-item-card:: Input and data
- :link: data/index
- :link-type: doc
-
- Learn the input grammar, trajectory conventions and output formats.
-
- .. grid-item-card:: Command reference
- :link: reference/cli
- :link-type: doc
-
- Inspect every command, positional argument and optional flag.
-
- .. grid-item-card:: Python API
- :link: reference/api
- :link-type: doc
-
- Integrate analyses and readers into Python workflows.
+* :doc:`analyses/index` compares the physical observables and required data.
+* :doc:`data/index` defines input grammar, trajectory conventions and table
+ formats.
+* :doc:`reference/cli` lists commands and options.
+* :doc:`reference/api` identifies the Python analysis and I/O entry points.
diff --git a/docs/source/index.rst b/docs/source/index.rst
index dee90b6c..f34610a5 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -26,47 +26,31 @@ XVG. Repeat ``--export`` to write several formats in the same run.
$ pqanalysis rdf rdf.in --export rdf.csv --export rdf.xvg
-Documentation
--------------
-
-.. grid:: 1 2 3 3
- :gutter: 2
-
- .. grid-item-card:: Getting started
- :link: getting-started
- :link-type: doc
-
- Install PQAnalysis and run a first radial-distribution calculation.
-
- .. grid-item-card:: Analyses
- :link: analyses/index
- :link-type: doc
-
- RDF, MSD, VACF, spectra, normal modes and momentum diagnostics.
-
- .. grid-item-card:: Data and conversion
- :link: data/index
- :link-type: doc
-
- Input syntax, trajectories, selections and scientific table formats.
-
- .. grid-item-card:: Command line
- :link: reference/cli
- :link-type: doc
-
- Analysis, conversion and trajectory command reference.
-
- .. grid-item-card:: Python API
- :link: reference/api
- :link-type: doc
-
- Curated entry points and the complete generated package reference.
-
- .. grid-item-card:: Development
- :link: developerGuide/developerGuide
- :link-type: doc
-
- Branching, tests, documentation checks and contribution conventions.
+Analysis methods
+----------------
+
+.. list-table:: Implemented observables
+ :header-rows: 1
+ :widths: 24 38 38
+
+ * - Method
+ - Required data
+ - Reported quantity
+ * - :doc:`Radial distribution `
+ - Positions and periodic cell
+ - :math:`g_{AB}(r)` and cumulative coordination
+ * - :doc:`Mean square displacement `
+ - Positions and periodic cell
+ - Cartesian MSD and diffusion fits
+ * - :doc:`VACF and spectra `
+ - Velocities, sampling interval and optional charges
+ - Normalized correlation and wavenumber spectrum
+ * - :doc:`Vibrational analysis `
+ - Structure, masses and Cartesian Hessian
+ - Normal modes, wavenumbers and optional IR intensities
+ * - :doc:`Momentum diagnostic `
+ - Velocities and atomic masses
+ - Frame-resolved total linear momentum
Scientific output
-----------------
@@ -83,8 +67,8 @@ Unicode symbols and units describe the physical quantities.
# UNITS Š1 1 ų pairs
0.5 0.0 0.0 0.0 -0.05026548245743666
-See :ref:`analysisOutputFiles` for every column, normalization convention and
-conversion path.
+See :ref:`analysisOutputFiles` for column definitions, normalization
+conventions and conversion behavior.
.. toctree::
:hidden:
diff --git a/docs/source/reference/api.rst b/docs/source/reference/api.rst
index 71ca3973..63665570 100644
--- a/docs/source/reference/api.rst
+++ b/docs/source/reference/api.rst
@@ -24,44 +24,24 @@ and are the simplest integration points:
Package areas
-------------
-.. grid:: 1 2 3 3
- :gutter: 2
-
- .. grid-item-card:: Analysis API
- :link: ../code/PQAnalysis.analysis
- :link-type: doc
-
- Calculations, input readers, result models and output writers.
-
- .. grid-item-card:: Input and output
- :link: ../code/PQAnalysis.io
- :link-type: doc
-
- Trajectory, restart, topology and simulation-file readers and writers.
-
- .. grid-item-card:: Trajectories
- :link: ../code/PQAnalysis.traj
- :link-type: doc
-
- Engine formats, trajectory containers and high-level operations.
-
- .. grid-item-card:: Atomic systems
- :link: ../code/PQAnalysis.atomic_system
- :link-type: doc
-
- Atomic coordinates, cells and topology-bearing systems.
-
- .. grid-item-card:: Topology and selection
- :link: ../code/PQAnalysis.topology
- :link-type: doc
-
- Selections, residues, bonded topology and SHAKE definitions.
-
- .. grid-item-card:: Complete package index
- :link: ../code/PQAnalysis
- :link-type: doc
-
- Every generated module, class, function and exception.
+.. list-table:: Generated package reference
+ :header-rows: 1
+ :widths: 34 66
-Use the curated analysis guides for physical conventions and the generated
-reference for signatures and implementation-level details.
+ * - Package
+ - Scope
+ * - :doc:`Analysis <../code/PQAnalysis.analysis>`
+ - Calculations, input readers, result models and output writers
+ * - :doc:`Input and output <../code/PQAnalysis.io>`
+ - Trajectory, restart, topology and simulation-file readers and writers
+ * - :doc:`Trajectories <../code/PQAnalysis.traj>`
+ - Engine formats, trajectory containers and high-level operations
+ * - :doc:`Atomic systems <../code/PQAnalysis.atomic_system>`
+ - Coordinates, cells and topology-bearing systems
+ * - :doc:`Topology and selection <../code/PQAnalysis.topology>`
+ - Selections, residues, bonded topology and SHAKE definitions
+ * - :doc:`Package index <../code/PQAnalysis>`
+ - Generated module hierarchy
+
+Use the analysis guides for physical conventions and the generated reference
+for signatures and implementation details.
diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst
index 239dd118..8c7373ed 100644
--- a/docs/source/reference/index.rst
+++ b/docs/source/reference/index.rst
@@ -5,26 +5,10 @@ Use the command reference for shell workflows and the Python API reference for
library integration. Scientific output definitions remain centralized so CLI
and API users share the same field names, units and normalization conventions.
-.. grid:: 1 2 3 3
- :gutter: 2
-
- .. grid-item-card:: Command line
- :link: cli
- :link-type: doc
-
- Analysis, format-conversion and simulation-support commands.
-
- .. grid-item-card:: Python API
- :link: api
- :link-type: doc
-
- Curated public entry points and the complete package reference.
-
- .. grid-item-card:: Output schemas
- :link: ../userGuide/analysisOutputFiles
- :link-type: doc
-
- Stable fields, symbols, units and file-format behavior.
+* :doc:`cli` covers analysis, conversion and simulation-support commands.
+* :doc:`api` lists public analysis functions and generated package modules.
+* :ref:`analysisOutputFiles` specifies table fields, symbols, units and
+ serialization formats.
.. toctree::
:hidden:
diff --git a/docs/source/userGuide/userGuide.rst b/docs/source/userGuide/userGuide.rst
index b40c8280..de7e2886 100644
--- a/docs/source/userGuide/userGuide.rst
+++ b/docs/source/userGuide/userGuide.rst
@@ -5,31 +5,9 @@
User Guide
==========
-The PQAnalysis user documentation is organized by task:
+This compatibility page points to the current task-oriented documentation:
-.. grid:: 1 2 2 2
- :gutter: 2
-
- .. grid-item-card:: Getting started
- :link: ../getting-started
- :link-type: doc
-
- Installation, first RDF calculation and output formats.
-
- .. grid-item-card:: Analyses
- :link: ../analyses/index
- :link-type: doc
-
- Scientific definitions, input examples and interpretation guidance.
-
- .. grid-item-card:: Data and conversion
- :link: ../data/index
- :link-type: doc
-
- Input grammar, trajectories, selections and scientific tables.
-
- .. grid-item-card:: Reference
- :link: ../reference/index
- :link-type: doc
-
- Command-line options, Python APIs and output schemas.
+* :doc:`../getting-started`: installation, first RDF calculation and outputs
+* :doc:`../analyses/index`: estimators, assumptions and interpretation
+* :doc:`../data/index`: input grammar, trajectories and scientific tables
+* :doc:`../reference/index`: command-line and Python interfaces
diff --git a/pyproject.toml b/pyproject.toml
index 4b9c2df8..e9a0c594 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -45,9 +45,9 @@ dev = [
]
docs = [
"furo>=2024.8.6,<2027",
+ "matplotlib>=3.9,<4",
"sphinx>=8,<9",
"sphinx-copybutton>=0.5,<1",
- "sphinx-design>=0.6,<1",
"sphinx-sitemap",
"breathe",
"myst-parser",
From 887af1d10e8545cb1c91fa20e44a7ec42832d689 Mon Sep 17 00:00:00 2001
From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com>
Date: Fri, 7 Aug 2026 13:27:21 +0200
Subject: [PATCH 3/7] docs: expose developer interfaces
---
PQAnalysis/io/restart_file/api.py | 2 +-
README.md | 18 ++-
docs/source/_static/css/custom.css | 103 ++++++++++++
docs/source/analyses/index.rst | 4 +-
docs/source/data/index.rst | 4 +-
.../source/developerGuide/adding-analysis.rst | 103 ++++++++++++
docs/source/developerGuide/architecture.rst | 89 +++++++++++
docs/source/developerGuide/developerGuide.rst | 146 ++++++++++--------
docs/source/developerGuide/release.rst | 72 +++++++++
docs/source/developerGuide/validation.rst | 91 +++++++++++
docs/source/getting-started.rst | 6 +-
docs/source/index.rst | 53 ++++---
docs/source/reference/api.rst | 46 +++---
docs/source/reference/functions.rst | 84 ++++++++++
docs/source/reference/index.rst | 12 +-
docs/source/userGuide/userGuide.rst | 4 +-
16 files changed, 713 insertions(+), 124 deletions(-)
create mode 100644 docs/source/developerGuide/adding-analysis.rst
create mode 100644 docs/source/developerGuide/architecture.rst
create mode 100644 docs/source/developerGuide/release.rst
create mode 100644 docs/source/developerGuide/validation.rst
create mode 100644 docs/source/reference/functions.rst
diff --git a/PQAnalysis/io/restart_file/api.py b/PQAnalysis/io/restart_file/api.py
index 7d49d9c1..6d8b1e31 100644
--- a/PQAnalysis/io/restart_file/api.py
+++ b/PQAnalysis/io/restart_file/api.py
@@ -62,7 +62,7 @@ def write_restart_file(
mode: FileWritingMode | str = 'w'
) -> None:
"""
- API function for reading a restart file.
+ Write an atomic system to a restart file.
Parameters
----------
diff --git a/README.md b/README.md
index bd4da712..20965f3b 100644
--- a/README.md
+++ b/README.md
@@ -19,18 +19,24 @@ Install with pip:
## Development
-Clone the PQAnalysis GitHub repository and navigate into the directory:
+Clone the repository and install the development, test and documentation
+dependencies in an isolated environment:
git clone https://github.com/MolarVerse/PQAnalysis.git
cd PQAnalysis
+ python -m venv .venv
+ source .venv/bin/activate
+ python -m pip install -e ".[dev,test,docs]"
-Install in editable mode with test dependencies:
+Run the test suite with both debug and release runtime type checking:
- pip install -e ".[test]"
+ bash pytest.sh
-Run the test suite:
-
- python -m pytest
+The [developer documentation](https://molarverse.github.io/PQAnalysis/developerGuide/developerGuide.html)
+covers package architecture, adding an analysis, scientific validation and the
+tag-driven release process. The
+[function index](https://molarverse.github.io/PQAnalysis/reference/functions.html)
+lists the supported Python entry points directly.
Use squash merges for pull requests. The pull request title becomes the commit
message on the target branch, so PR titles must follow
diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css
index affc1368..1f65228e 100644
--- a/docs/source/_static/css/custom.css
+++ b/docs/source/_static/css/custom.css
@@ -56,6 +56,109 @@ img.plot-directive + figcaption {
overflow-x: auto;
}
+@media (max-width: 44rem) {
+ article table.autosummary,
+ article table.pq-record-table {
+ display: block;
+ width: 100%;
+ }
+
+ table.autosummary,
+ table.autosummary tbody,
+ table.autosummary tr,
+ table.autosummary td,
+ table.pq-record-table,
+ table.pq-record-table tbody,
+ table.pq-record-table tr,
+ table.pq-record-table td {
+ display: block;
+ width: 100%;
+ }
+
+ table.autosummary,
+ table.pq-record-table {
+ border: 0;
+ }
+
+ table.autosummary tr,
+ table.pq-record-table tr {
+ padding-block: 0.7rem;
+ border-bottom: 1px solid var(--color-foreground-border);
+ }
+
+ table.autosummary td,
+ table.pq-record-table td {
+ padding: 0.2rem 0;
+ border: 0;
+ }
+
+ table.autosummary td:first-child,
+ table.pq-record-table td:first-child {
+ font-weight: 650;
+ }
+
+ table.autosummary td:last-child {
+ color: var(--color-foreground-secondary);
+ }
+
+ table.pq-record-table thead {
+ display: none;
+ }
+
+ table.pq-record-table td:not(:first-child)::before {
+ display: block;
+ margin-top: 0.35rem;
+ color: var(--color-foreground-secondary);
+ font-size: 0.75rem;
+ font-weight: 650;
+ text-transform: uppercase;
+ }
+
+ table.pq-method-table td:nth-child(2)::before,
+ table.pq-observable-table td:nth-child(2)::before {
+ content: "Required data";
+ }
+
+ table.pq-method-table td:nth-child(3)::before,
+ table.pq-observable-table td:nth-child(3)::before {
+ content: "Reported quantity";
+ }
+
+ table.pq-extension-table td:nth-child(2)::before {
+ content: "Primary location";
+ }
+
+ table.pq-extension-table td:nth-child(3)::before {
+ content: "Contract";
+ }
+
+ table.pq-package-table td:nth-child(2)::before {
+ content: "Responsibility";
+ }
+
+ table.pq-validation-table td:nth-child(2)::before {
+ content: "Purpose";
+ }
+
+ table.pq-validation-table td:nth-child(3)::before {
+ content: "Suitable reference";
+ }
+
+ table.pq-types-table td:nth-child(2)::before {
+ content: "Role";
+ }
+
+ table.pq-package-reference-table td:nth-child(2)::before {
+ content: "Scope";
+ }
+}
+
+@media (max-width: 24rem) {
+ article h1 {
+ font-size: 2rem;
+ }
+}
+
table.analysis-output-columns {
min-width: 640px;
width: 100%;
diff --git a/docs/source/analyses/index.rst b/docs/source/analyses/index.rst
index 6837b88f..481e54e8 100644
--- a/docs/source/analyses/index.rst
+++ b/docs/source/analyses/index.rst
@@ -10,6 +10,7 @@ Choose by input data
--------------------
.. list-table:: Analysis inputs and primary observables
+ :class: pq-record-table pq-observable-table
:header-rows: 1
:widths: 24 32 44
@@ -34,7 +35,8 @@ Choose by input data
The method pages define each estimator, its assumptions and its interpretation
limits. File columns and units are specified once in
-:ref:`analysisOutputFiles`.
+:ref:`analysisOutputFiles`. Programmatic entry points are listed in the
+:doc:`../reference/functions`.
.. toctree::
:hidden:
diff --git a/docs/source/data/index.rst b/docs/source/data/index.rst
index 41df11aa..f6a2c24b 100644
--- a/docs/source/data/index.rst
+++ b/docs/source/data/index.rst
@@ -1,5 +1,5 @@
-Data and Conversion
-===================
+Files and Formats
+=================
PQAnalysis separates simulation data, analysis configuration and output-table
serialization. File extensions select output formats, while input content and
diff --git a/docs/source/developerGuide/adding-analysis.rst b/docs/source/developerGuide/adding-analysis.rst
new file mode 100644
index 00000000..00426479
--- /dev/null
+++ b/docs/source/developerGuide/adding-analysis.rst
@@ -0,0 +1,103 @@
+Adding an Analysis
+==================
+
+Use an existing complete analysis, such as RDF or MSD, as the structural
+reference. Keep the scientific estimator independent from its CLI and file
+format adapters.
+
+1. Define the scientific contract
+---------------------------------
+
+State the observable, normalization, units, periodic-boundary treatment,
+selection semantics and returned array shapes before implementing the
+calculation. Decide which behavior reproduces a legacy tool and which behavior
+is a corrected or newly defined method.
+
+The analysis guide and tests must use the same definitions. A numerical result
+without its normalization and units is not a complete interface.
+
+2. Implement the analysis package
+---------------------------------
+
+A file-driven analysis typically owns these modules:
+
+.. code-block:: text
+
+ PQAnalysis/analysis//
+ __init__.py
+ api.py
+ .py
+ _input_file_reader.py
+ _output_file_writer.py
+ exceptions.py
+
+The analysis class or numerical function owns the calculation. The input reader
+validates configuration and the writer serializes results. Avoid importing CLI
+code from the analysis package.
+
+If a compiled kernel is required, provide a Python or NumPy fallback with the
+same callable signature. Import the compiled implementation first and fall back
+only when it is unavailable, following the RDF, MSD and VACF packages.
+
+3. Define inputs and outputs
+----------------------------
+
+Add input keys to the analysis input reader with explicit types, defaults and
+validation. Required files should be validated before the trajectory is
+processed. Keep aliases only when they preserve an established input contract.
+
+Define output columns in ``PQAnalysis/analysis/_output_schemas.py`` using
+:class:`~PQAnalysis.analysis.output.AnalysisColumn` and
+:class:`~PQAnalysis.analysis.output.AnalysisSchema`. Field identifiers are ASCII
+programmatic names; symbols and units may use Unicode scientific notation.
+
+The data writer should subclass
+:class:`~PQAnalysis.analysis.output.AnalysisDataWriter`, create an
+:class:`~PQAnalysis.analysis.output.AnalysisTable` from the numerical columns,
+and delegate CSV, TSV and XVG exports to the common writer. Preserve a legacy
+native row format only when compatibility requires it.
+
+4. Add the public API
+---------------------
+
+The function in ``api.py`` is the shared orchestration layer. It should:
+
+1. read and validate the analysis input;
+2. construct trajectory, structure or Hessian readers;
+3. construct every output writer so path conflicts fail early;
+4. instantiate and run the scientific analysis;
+5. write the result and return useful in-memory data where appropriate.
+
+Export the function and supported result types from the analysis package
+``__init__.py`` and, for a general analysis workflow, from
+``PQAnalysis.analysis``. Add the callable to :doc:`../reference/functions`.
+
+5. Add the CLI
+--------------
+
+Implement a ``CLIBase`` subclass in ``PQAnalysis/cli/.py``. Its
+``add_arguments`` method defines only command-line parsing; ``run`` calls the
+public API function. Reuse common arguments from
+``PQAnalysis/cli/_argument_parser.py``, including repeatable ``--export`` for
+analysis tables.
+
+Register the class in the dispatch dictionary in ``PQAnalysis/cli/main.py``.
+Add a ``[project.scripts]`` entry in ``pyproject.toml`` only when a standalone
+executable is part of the supported interface.
+
+6. Add evidence and documentation
+---------------------------------
+
+The minimum complete change includes:
+
+* analytical or independently computed numerical tests;
+* legacy parity tests when compatibility is claimed;
+* compiled-kernel and fallback parity where both exist;
+* input-reader validation and default tests;
+* API and CLI end-to-end tests;
+* native output and CSV, TSV and XVG tests;
+* existing-file failure tests for every output path;
+* an analysis page defining equations, assumptions, inputs and interpretation;
+* entries in the function index, command reference and output-schema page.
+
+Follow :doc:`validation` for reference-data provenance and tolerance rules.
diff --git a/docs/source/developerGuide/architecture.rst b/docs/source/developerGuide/architecture.rst
new file mode 100644
index 00000000..cb616ee6
--- /dev/null
+++ b/docs/source/developerGuide/architecture.rst
@@ -0,0 +1,89 @@
+Architecture
+============
+
+PQAnalysis separates scientific computation from file orchestration. An
+input-file analysis normally follows this path:
+
+.. code-block:: text
+
+ CLI class
+ -> public API function
+ -> analysis input reader
+ -> trajectory, structure or Hessian reader
+ -> analysis object and numerical kernel
+ -> AnalysisTable with an AnalysisSchema
+ -> native writer and optional CSV, TSV or XVG writers
+
+The command line and Python API therefore share the calculation, validation and
+output code. A CLI class should parse arguments and call a public API function;
+it should not contain a second implementation of the scientific method.
+
+Package boundaries
+------------------
+
+.. list-table:: Source ownership
+ :class: pq-record-table pq-package-table
+ :header-rows: 1
+ :widths: 30 70
+
+ * - Path
+ - Responsibility
+ * - ``PQAnalysis/analysis/``
+ - Scientific estimators, spectra, result models and analysis-table output
+ * - ``PQAnalysis/cli/``
+ - Argument definitions and dispatch to public API functions
+ * - ``PQAnalysis/io/``
+ - Simulation-file readers, writers and format conversion
+ * - ``PQAnalysis/traj/``
+ - Trajectory containers, engine formats and trajectory-wide checks
+ * - ``PQAnalysis/atomic_system/`` and ``PQAnalysis/core/``
+ - Atomic coordinates, cells, atoms and residues
+ * - ``PQAnalysis/topology/``
+ - Selections, molecular identity and bonded topology
+
+The :doc:`../reference/functions` page lists callable entry points. The
+:doc:`../reference/api` page exposes the classes and generated modules behind
+them.
+
+Public contracts
+----------------
+
+Treat the following as compatibility surfaces:
+
+* non-underscored functions and classes deliberately imported by a package
+ ``__init__.py``;
+* command names, arguments and input-file keys;
+* analysis result attributes and array shapes;
+* output field identifiers, symbols, units and column order;
+* accepted trajectory and structure formats;
+* exception types raised for invalid user input.
+
+Modules, functions and attributes beginning with an underscore are internal.
+Changing a public contract requires tests, documentation and either backward
+compatibility or an explicit deprecation path.
+
+Numerical kernels
+-----------------
+
+RDF, MSD and VACF use compiled Cython kernels when available and NumPy/Python
+fallbacks otherwise. The compiled and fallback implementations must keep the
+same signature, normalization and edge-case behavior. A kernel change therefore
+requires tests of both implementations and a direct parity test between them.
+
+File parsing and logging belong outside numerical kernels. Kernels should accept
+validated arrays and scalar parameters and return numerical results without
+creating files.
+
+Analysis-table contract
+-----------------------
+
+Scientific columns are defined by
+``PQAnalysis/analysis/_output_schemas.py``. Each
+:class:`~PQAnalysis.analysis.output.AnalysisSchema` records stable ASCII field
+identifiers, display symbols, units and an optional xmgrace projection.
+
+Writers convert numerical results into an
+:class:`~PQAnalysis.analysis.output.AnalysisTable`. Native formatting may retain
+legacy row layout, while CSV, TSV and XVG use the same schema. Construct all
+requested writers before the calculation starts so an existing output path
+fails before expensive work or partial output occurs.
diff --git a/docs/source/developerGuide/developerGuide.rst b/docs/source/developerGuide/developerGuide.rst
index 13f1d547..0dee40ba 100644
--- a/docs/source/developerGuide/developerGuide.rst
+++ b/docs/source/developerGuide/developerGuide.rst
@@ -3,15 +3,50 @@
Development
===========
-PQAnalysis uses a ``dev`` integration branch and releases from ``main``.
-Feature and fix pull requests normally target ``dev``; release pull requests
-merge ``dev`` into ``main``.
-
-Local setup
------------
-
-Clone the repository and install editable development, test and documentation
-dependencies:
+PQAnalysis uses a ``dev`` integration branch and releases from ``main``. This
+section documents the code boundaries and evidence required to extend the
+package, not only the mechanics of opening a pull request.
+
+Extension path
+--------------
+
+.. list-table:: Analysis implementation path
+ :class: pq-record-table pq-extension-table
+ :header-rows: 1
+ :widths: 24 38 38
+
+ * - Stage
+ - Primary location
+ - Contract
+ * - Scientific method
+ - ``PQAnalysis/analysis//``
+ - Estimator, normalization, units and result shape
+ * - Python interface
+ - ``PQAnalysis/analysis//api.py``
+ - Validated orchestration shared with the CLI
+ * - Command line
+ - ``PQAnalysis/cli/.py``
+ - Arguments and dispatch, without duplicate computation
+ * - Scientific output
+ - ``PQAnalysis/analysis/_output_schemas.py``
+ - Stable fields, symbols, units and plot projection
+ * - Evidence
+ - ``tests/analysis//`` and ``tests/data//``
+ - Analytical, independent, parity and end-to-end tests
+
+.. toctree::
+ :maxdepth: 1
+
+ architecture
+ adding-analysis
+ validation
+ release
+
+Local environment
+-----------------
+
+Install the package with development, test and documentation dependencies in an
+isolated environment:
.. code-block:: console
@@ -21,90 +56,69 @@ dependencies:
$ source .venv/bin/activate
$ python -m pip install -e ".[dev,test,docs]"
-Keep changes focused and add tests at the same ownership boundary as the
-behavior being changed.
-
-Tests
------
+Quality gates
+-------------
-The full test script runs the suite with runtime type checking enabled and
-again with release settings:
+``pytest.sh`` runs the suite with debug runtime type checking and repeats it
+with release settings:
.. code-block:: console
$ bash pytest.sh
+ $ bash pytest.sh tests/analysis/rdf -q
-For a focused iteration, pass ordinary pytest arguments:
+Run pylint against the package and retain a score above the CI threshold of
+9.75:
.. code-block:: console
- $ bash pytest.sh tests/analysis/rdf -q
-
-Documentation
--------------
+ $ python -m pylint PQAnalysis --persistent n
-Build the complete documentation with warnings treated as errors:
+Public Python interfaces use NumPy-style docstrings. Document parameters,
+returns, raised exceptions, units and array shapes. Inspect coverage with:
.. code-block:: console
- $ python -m sphinx -W --keep-going \
- -b html docs/source docs/build/html
+ $ docstr-coverage PQAnalysis
-Check internal and external links separately:
+Documentation
+-------------
+
+Build the complete documentation and check links with warnings treated as
+errors:
.. code-block:: console
- $ python -m sphinx -W --keep-going \
+ $ python -m sphinx -E -W --keep-going \
+ -b html docs/source docs/build/html
+ $ python -m sphinx -E -W --keep-going \
-b linkcheck docs/source docs/build/linkcheck
The API reference is generated from package modules when Sphinx starts. Do not
-hand-edit generated files under ``docs/source/code`` unless the generator or
-its templates are being changed. User-facing scientific conventions belong in
-the maintained analysis, data and reference pages.
-
-Documentation structure
------------------------
-
-* ``getting-started.rst`` provides the shortest working path.
-* ``analyses/`` explains physical definitions, inputs and interpretation.
-* ``_plots/`` contains executable Matplotlib figures built from documented
- analytic models or versioned validation fixtures.
-* ``data/`` covers file grammar, trajectories, selections and conversion.
-* ``reference/`` indexes CLI and Python interfaces.
-* ``userGuide/analysisOutputFiles.rst`` is the canonical output-schema source.
-* ``code/`` is generated API material.
-
-Every analysis guide should state the physical quantity, assumptions, units,
-minimal input, output fields and interpretation limits. Keep duplicated option
-tables in generated API documentation rather than copying them into several
-manual pages. Figure captions must identify their data source and distinguish
-analytic schematics, validation fixtures and physical benchmark results.
+hand-edit generated files under ``docs/source/code``. Add public callables to
+:doc:`../reference/functions`, and put implementation-level guidance in this
+development section.
+
+Executable figures under ``docs/source/_plots`` must be deterministic. Captions
+must distinguish analytic schematics, versioned validation fixtures and
+physical benchmark results.
Pull requests
-------------
-Pull requests should be reviewer-readable and use a Conventional Commits title,
-for example ``feat: add a new analysis command`` or
-``fix(io): handle missing trajectory data``. The repository validates the PR
-title and uses it as the squash-merge commit message.
+Feature and fix pull requests normally target ``dev``. Release pull requests
+merge ``dev`` into ``main``. Use a Conventional Commits PR title, such as
+``feat: add a new analysis command`` or
+``fix(io): handle missing trajectory data``; the title becomes the squash-merge
+commit message.
-The optional local commit-message hook provides earlier feedback:
+Enable the optional local commit-message hook with:
.. code-block:: console
$ git config core.hooksPath .githooks
-Before requesting review, run the focused tests for the change and every
-relevant strict documentation build. CI publishes documentation only from
-``main``; pull requests and ``dev`` pushes build it without deploying.
-
-Docstrings
-----------
-
-Public Python interfaces use NumPy-style docstrings. Document parameters,
-returns, raised exceptions, units and array shapes precisely. Documentation
-coverage can be inspected with:
-
-.. code-block:: console
-
- $ docstr-coverage PQAnalysis
+Before requesting review, run the focused tests for the modified ownership
+boundary and every relevant strict documentation build. Pull requests and
+``dev`` pushes build documentation without deploying it; deployment occurs
+from ``main``.
diff --git a/docs/source/developerGuide/release.rst b/docs/source/developerGuide/release.rst
new file mode 100644
index 00000000..5000f641
--- /dev/null
+++ b/docs/source/developerGuide/release.rst
@@ -0,0 +1,72 @@
+Release Process
+===============
+
+PQAnalysis uses ``dev`` as the integration branch and releases from ``main``.
+Version strings are derived from Git tags by ``setuptools_scm``; do not edit the
+generated ``PQAnalysis/_version.py`` file.
+
+Release boundary
+----------------
+
+The release workflow matches every pushed tag. A tag push can publish to PyPI
+and TestPyPI, create a GitHub release, sign release artifacts and update
+``CHANGELOG.md`` on ``main``.
+
+.. warning::
+
+ Treat ``git push origin vX.Y.Z`` as the publication action. Deleting a Git
+ tag does not remove an uploaded Python distribution.
+
+Pre-release checks
+------------------
+
+1. Open a release pull request from ``dev`` to ``main``.
+2. Confirm that the release PR contains only reviewed integration changes.
+3. Run both runtime-type-checking configurations with ``bash pytest.sh``.
+4. Build the HTML documentation and link check with warnings as errors.
+5. Confirm the Conventional Commits history produces meaningful release notes.
+6. Verify the intended version is greater than every existing release tag.
+
+The local verification commands are:
+
+.. code-block:: console
+
+ $ git fetch origin --tags
+ $ bash pytest.sh
+ $ python -m sphinx -E -W --keep-going \
+ -b html docs/source docs/build/html
+ $ python -m sphinx -E -W --keep-going \
+ -b linkcheck docs/source docs/build/linkcheck
+
+Tagging
+-------
+
+After the release PR is merged and the ``main`` checks pass, tag the verified
+``main`` commit with the existing ``vMAJOR.MINOR.PATCH`` convention:
+
+.. code-block:: console
+
+ $ git switch main
+ $ git pull --ff-only origin main
+ $ git tag -a vX.Y.Z -m "PQAnalysis vX.Y.Z"
+ $ git push origin vX.Y.Z
+
+Use a major version for incompatible public API or file-contract changes, a
+minor version for backward-compatible functionality and a patch version for
+backward-compatible fixes.
+
+Publication verification
+------------------------
+
+Do not consider the release complete until all of these are confirmed:
+
+* the release workflow succeeded;
+* the new version is available from PyPI;
+* the GitHub release contains the signed distribution artifacts;
+* ``CHANGELOG.md`` was updated on ``main``;
+* the documentation workflow deployed the verified ``main`` build;
+* a clean environment can install the published version and run
+ ``pqanalysis --version``.
+
+Published PyPI files are immutable. Correct a defective release with a new
+patch release rather than moving or reusing its tag.
diff --git a/docs/source/developerGuide/validation.rst b/docs/source/developerGuide/validation.rst
new file mode 100644
index 00000000..fe775568
--- /dev/null
+++ b/docs/source/developerGuide/validation.rst
@@ -0,0 +1,91 @@
+Scientific Validation
+=====================
+
+Tests should identify what kind of evidence they provide. Agreement with a
+previous implementation establishes compatibility; it does not by itself
+establish physical correctness.
+
+Evidence classes
+----------------
+
+.. list-table:: Validation evidence
+ :class: pq-record-table pq-validation-table
+ :header-rows: 1
+ :widths: 25 35 40
+
+ * - Evidence
+ - Purpose
+ - Suitable reference
+ * - Analytical invariant
+ - Verify definitions and limiting cases
+ - Hand-derived value, conservation law or exactly soluble system
+ * - Independent implementation
+ - Detect shared implementation errors
+ - ASE, a direct NumPy expression or another documented program
+ * - Legacy parity
+ - Preserve established PQ tool behavior
+ - Output generated by the named legacy executable and input
+ * - Kernel parity
+ - Keep optimized and fallback paths equivalent
+ - Direct comparison on identical arrays and parameters
+ * - End-to-end behavior
+ - Verify parsing, orchestration and serialization
+ - CLI/API run with versioned fixtures and expected output
+
+Use more than one evidence class for a new scientific method. A reference file
+produced by the implementation under test is not independent validation.
+
+Reference-data provenance
+-------------------------
+
+Store compact, deterministic fixtures under ``tests/data//``. The test
+module or a README beside the data must record:
+
+* the program and version that generated the reference;
+* the complete source input and relevant options;
+* the physical units and column meanings;
+* any precision loss caused by text serialization;
+* the reason for the selected numerical tolerance.
+
+Do not replace a reference file merely to make a failing test pass. A reference
+change must be reviewable as either a corrected scientific definition, an
+intentional compatibility change or a newly generated independent benchmark.
+
+Numerical tolerances
+--------------------
+
+Prefer exact equality for integer counts, field names and deterministic text.
+For floating-point data, choose ``rtol`` and ``atol`` from the numerical method,
+reference precision and expected magnitude. Record relaxed tolerances next to
+the assertion. Do not use one package-wide tolerance for observables with
+different scales.
+
+Fast kernels may accumulate values in a different order from NumPy fallbacks.
+Their parity tolerance should cover the expected floating-point summation
+difference, not unrelated algorithmic changes.
+
+Test commands
+-------------
+
+``pytest.sh`` runs the requested tests once with debug runtime type checking and
+once with release settings:
+
+.. code-block:: console
+
+ $ bash pytest.sh tests/analysis/rdf -q
+ $ bash pytest.sh tests/analysis/msd -q
+ $ bash pytest.sh tests/analysis/vacf -q
+
+Run the complete suite before review:
+
+.. code-block:: console
+
+ $ bash pytest.sh
+
+Documentation figures
+---------------------
+
+Executable figures under ``docs/source/_plots`` may use an analytic model or a
+versioned validation fixture. Their captions must state which one. A schematic
+must not be presented as simulation output, and a legacy parity fixture must not
+be described as an independent physical benchmark.
diff --git a/docs/source/getting-started.rst b/docs/source/getting-started.rst
index be5ba7aa..955bd345 100644
--- a/docs/source/getting-started.rst
+++ b/docs/source/getting-started.rst
@@ -72,7 +72,9 @@ Next steps
----------
* :doc:`analyses/index` compares the physical observables and required data.
-* :doc:`data/index` defines input grammar, trajectory conventions and table
- formats.
+* :doc:`reference/functions` lists public Python workflows and numerical
+ functions.
* :doc:`reference/cli` lists commands and options.
* :doc:`reference/api` identifies the Python analysis and I/O entry points.
+* :doc:`developerGuide/developerGuide` documents architecture, extension and
+ validation.
diff --git a/docs/source/index.rst b/docs/source/index.rst
index f34610a5..9f8c4da0 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -7,7 +7,7 @@ velocities and Hessians, then produces documented scientific tables for
structural, transport and vibrational observables.
:doc:`Get started ` | :doc:`Choose an analysis ` |
-:doc:`Work with data ` | :doc:`Command reference `
+:doc:`Python functions ` | :doc:`Develop PQAnalysis `
Quick start
-----------
@@ -30,6 +30,7 @@ Analysis methods
----------------
.. list-table:: Implemented observables
+ :class: pq-record-table pq-method-table
:header-rows: 1
:widths: 24 38 38
@@ -52,31 +53,47 @@ Analysis methods
- Velocities and atomic masses
- Frame-resolved total linear momentum
-Scientific output
------------------
+Python interface
+----------------
+
+The public analysis functions use the same validated input readers and
+scientific kernels as the command line:
+
+.. code-block:: python
-Native analysis tables retain their established numeric layout and add a
-compact UTF-8 metadata header. Stable ASCII field names support scripts while
-Unicode symbols and units describe the physical quantities.
+ from PQAnalysis.analysis import rdf, read_analysis_table
-.. code-block:: text
+ rdf("rdf.in", export_files=["rdf.csv"])
+ table = read_analysis_table("rdf.csv")
- # PQAnalysis: Radial distribution function
- # FIELDS r_i g_r_i N_r_i g_r_i_dV_i H_i_minus_E_i
- # SYMBOLS rᵢ g(rᵢ) N(rᵢ) g(rᵢ)ΔVᵢ Hᵢ−Eᵢ
- # UNITS Š1 1 ų pairs
- 0.5 0.0 0.0 0.0 -0.05026548245743666
+The :doc:`function index ` exposes analysis workflows,
+numerical methods, scientific-table operations and simulation-file I/O without
+requiring navigation through the generated module tree.
+
+Development
+-----------
-See :ref:`analysisOutputFiles` for column definitions, normalization
-conventions and conversion behavior.
+New methods follow a documented path from estimator and validation evidence to
+the public API, CLI and schema-backed output. See
+:doc:`Adding an Analysis ` for the complete
+implementation checklist and :doc:`Architecture `
+for package ownership boundaries.
.. toctree::
:hidden:
:maxdepth: 2
- :caption: Documentation
+ :caption: Use PQAnalysis
getting-started
analyses/index
- data/index
- reference/index
- Development
+ Python Functions
+ Command Line
+ Files and Formats
+ Package Reference
+
+.. toctree::
+ :hidden:
+ :maxdepth: 2
+ :caption: Develop PQAnalysis
+
+ developerGuide/developerGuide
diff --git a/docs/source/reference/api.rst b/docs/source/reference/api.rst
index 63665570..fd5c00ce 100644
--- a/docs/source/reference/api.rst
+++ b/docs/source/reference/api.rst
@@ -1,30 +1,38 @@
-Python API
-==========
+Package Reference
+=================
-The public analysis wrappers accept the same input files as the command line
-and are the simplest integration points:
+Start with the :doc:`functions` page for callable analysis, numerical and I/O
+interfaces. This page maps the principal data types and generated module
+reference.
-.. list-table:: Analysis entry points
+Core types
+----------
+
+.. list-table:: Principal data types
+ :class: pq-record-table pq-types-table
:header-rows: 1
:widths: 34 66
- * - Function
- - Purpose
- * - :func:`PQAnalysis.analysis.rdf.api.rdf`
- - Radial distribution analysis
- * - :func:`PQAnalysis.analysis.msd.api.msd`
- - Mean square displacement analysis
- * - :func:`PQAnalysis.analysis.vacf.api.vacf`
- - Velocity or charge-flux correlation analysis
- * - :func:`PQAnalysis.analysis.vibrational.api.vibrations`
- - Vibrational analysis from a structure and Hessian
- * - :func:`PQAnalysis.analysis.momentum.api.check_momentum`
- - Frame-resolved total linear momentum
+ * - Type
+ - Role
+ * - :class:`PQAnalysis.atomic_system.AtomicSystem`
+ - One structure with coordinates, cell and topology
+ * - :class:`PQAnalysis.traj.Trajectory`
+ - Ordered atomic-system frames
+ * - :class:`PQAnalysis.topology.Topology`
+ - Atoms, residues, molecular identity and bonded topology
+ * - :class:`PQAnalysis.topology.Selection`
+ - Atom selection parser and index resolution
+ * - :class:`PQAnalysis.analysis.output.AnalysisTable`
+ - Numerical analysis data coupled to scientific column metadata
+ * - :class:`PQAnalysis.analysis.output.AnalysisSchema`
+ - Stable fields, symbols, units and plot defaults
Package areas
-------------
.. list-table:: Generated package reference
+ :class: pq-record-table pq-package-reference-table
:header-rows: 1
:widths: 34 66
@@ -43,5 +51,5 @@ Package areas
* - :doc:`Package index <../code/PQAnalysis>`
- Generated module hierarchy
-Use the analysis guides for physical conventions and the generated reference
-for signatures and implementation details.
+Use the analysis guides for physical conventions, the function index for
+callable workflows and the generated reference for implementation details.
diff --git a/docs/source/reference/functions.rst b/docs/source/reference/functions.rst
new file mode 100644
index 00000000..73645e48
--- /dev/null
+++ b/docs/source/reference/functions.rst
@@ -0,0 +1,84 @@
+.. _function-index:
+
+Function Index
+==============
+
+This page lists the callable Python interfaces intended for direct use. The
+analysis wrappers accept the same input files as their command-line
+counterparts. Lower-level numerical functions operate on arrays or PQAnalysis
+objects and do not parse command-line arguments.
+
+Analysis workflows
+------------------
+
+.. autosummary::
+
+ ~PQAnalysis.analysis.rdf.api.rdf
+ ~PQAnalysis.analysis.msd.api.msd
+ ~PQAnalysis.analysis.vacf.api.vacf
+ ~PQAnalysis.analysis.vibrational.api.vibrations
+ ~PQAnalysis.analysis.momentum.api.check_momentum
+ ~PQAnalysis.analysis.spectrum_broadening.api.build_spectrum
+
+Numerical methods
+-----------------
+
+.. autosummary::
+
+ ~PQAnalysis.analysis.vacf.spectrum.apodization_window
+ ~PQAnalysis.analysis.vacf.spectrum.vacf_spectrum
+ ~PQAnalysis.analysis.spectrum_broadening.spectrum_broadening.alpha_from_fwhm
+ ~PQAnalysis.analysis.spectrum_broadening.spectrum_broadening.fwhm_from_alpha
+ ~PQAnalysis.analysis.spectrum_broadening.spectrum_broadening.wavenumber_grid
+ ~PQAnalysis.analysis.spectrum_broadening.spectrum_broadening.broaden
+ ~PQAnalysis.analysis.vibrational.vibrational_analysis.calculate
+ ~PQAnalysis.analysis.vibrational.vibrational_analysis.read_hessian_file
+ ~PQAnalysis.analysis.vibrational.vibrational_analysis.select_mode_indices
+
+Analysis tables
+---------------
+
+.. autosummary::
+
+ ~PQAnalysis.analysis.output.infer_output_format
+ ~PQAnalysis.analysis.output.read_analysis_table
+ ~PQAnalysis.analysis.output.write_analysis_table
+ ~PQAnalysis.analysis.output.convert_analysis_output
+
+Structure and trajectory I/O
+----------------------------
+
+.. autosummary::
+
+ ~PQAnalysis.io.traj_file.api.read_trajectory
+ ~PQAnalysis.io.traj_file.api.read_trajectory_generator
+ ~PQAnalysis.io.traj_file.api.write_trajectory
+ ~PQAnalysis.io.traj_file.api.calculate_frames_of_trajectory_file
+ ~PQAnalysis.io.restart_file.api.read_restart_file
+ ~PQAnalysis.io.restart_file.api.write_restart_file
+ ~PQAnalysis.io.gen_file.api.read_gen_file
+ ~PQAnalysis.io.gen_file.api.write_gen_file
+ ~PQAnalysis.io.topology_file.api.read_topology_file
+ ~PQAnalysis.io.topology_file.api.write_topology_file
+ ~PQAnalysis.io.box_reader.read_box
+ ~PQAnalysis.io.optimizer_file_reader.read_optimizer_file
+ ~PQAnalysis.io.write_api.write
+ ~PQAnalysis.io.write_api.write_box
+ ~PQAnalysis.traj.api.check_trajectory_pbc
+ ~PQAnalysis.traj.api.check_trajectory_vacuum
+
+Format conversion
+-----------------
+
+.. autosummary::
+
+ ~PQAnalysis.io.conversion_api.rst2xyz
+ ~PQAnalysis.io.conversion_api.xyz2rst
+ ~PQAnalysis.io.conversion_api.xyz2gen
+ ~PQAnalysis.io.conversion_api.gen2xyz
+ ~PQAnalysis.io.conversion_api.traj2box
+ ~PQAnalysis.io.conversion_api.traj2extxyz
+ ~PQAnalysis.io.conversion_api.traj2qmcfc
+
+See :doc:`api` for classes, enums, exceptions and the generated module
+hierarchy.
diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst
index 8c7373ed..3507129c 100644
--- a/docs/source/reference/index.rst
+++ b/docs/source/reference/index.rst
@@ -1,3 +1,5 @@
+:orphan:
+
Reference
=========
@@ -5,14 +7,8 @@ Use the command reference for shell workflows and the Python API reference for
library integration. Scientific output definitions remain centralized so CLI
and API users share the same field names, units and normalization conventions.
+* :doc:`functions` lists public Python functions by task.
* :doc:`cli` covers analysis, conversion and simulation-support commands.
-* :doc:`api` lists public analysis functions and generated package modules.
+* :doc:`api` maps core classes and generated package modules.
* :ref:`analysisOutputFiles` specifies table fields, symbols, units and
serialization formats.
-
-.. toctree::
- :hidden:
- :maxdepth: 1
-
- cli
- api
diff --git a/docs/source/userGuide/userGuide.rst b/docs/source/userGuide/userGuide.rst
index de7e2886..d826ab05 100644
--- a/docs/source/userGuide/userGuide.rst
+++ b/docs/source/userGuide/userGuide.rst
@@ -9,5 +9,7 @@ This compatibility page points to the current task-oriented documentation:
* :doc:`../getting-started`: installation, first RDF calculation and outputs
* :doc:`../analyses/index`: estimators, assumptions and interpretation
+* :doc:`../reference/functions`: public Python functions by task
+* :doc:`../reference/cli`: command-line interfaces
* :doc:`../data/index`: input grammar, trajectories and scientific tables
-* :doc:`../reference/index`: command-line and Python interfaces
+* :doc:`../developerGuide/developerGuide`: architecture and contribution work
From d0da85c05d2256af6c767dde25913d1a6b691702 Mon Sep 17 00:00:00 2001
From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com>
Date: Fri, 7 Aug 2026 13:59:04 +0200
Subject: [PATCH 4/7] docs: refine VACF notation and figure
---
docs/source/_plots/vacf.py | 26 ++++++++++++++-----
docs/source/analyses/index.rst | 2 +-
docs/source/analyses/vacf.rst | 5 +++-
docs/source/userGuide/analysisOutputFiles.rst | 2 +-
4 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/docs/source/_plots/vacf.py b/docs/source/_plots/vacf.py
index 80598b2e..8bbd64f8 100644
--- a/docs/source/_plots/vacf.py
+++ b/docs/source/_plots/vacf.py
@@ -6,7 +6,7 @@
from _style import COLORS, PROJECT_ROOT, apply_style
-apply_style((7.2, 5.1))
+apply_style((6.2, 5.5))
correlation = np.loadtxt(PROJECT_ROOT / "tests/data/vacf/vacf_ref.dat")
spectrum = np.loadtxt(
@@ -31,8 +31,15 @@
linestyle=":",
linewidth=1.0,
)
-correlation_axis.set_xlabel(r"Lag time $t$ / ps")
-correlation_axis.set_ylabel(r"$C_v(t)$")
+correlation_axis.set_title(
+ "(a) Normalized velocity autocorrelation",
+ loc="left",
+ fontsize=9.5,
+ fontweight="semibold",
+ pad=8,
+)
+correlation_axis.set_xlabel("Lag time, t / ps")
+correlation_axis.set_ylabel("Cᵥᵥ(t)")
correlation_axis.set_xlim(correlation[0, 0], correlation[-1, 0])
correlation_axis.set_ylim(-1.05, 1.05)
@@ -41,10 +48,17 @@
spectrum[:, 1],
color=COLORS["orange"],
)
-spectrum_axis.set_xlabel(r"Wavenumber $\tilde{\nu}$ / $\mathrm{cm}^{-1}$")
-spectrum_axis.set_ylabel("Amplitude / a.u.")
+spectrum_axis.set_title(
+ "(b) Hann-window cosine-transform spectrum",
+ loc="left",
+ fontsize=9.5,
+ fontweight="semibold",
+ pad=8,
+)
+spectrum_axis.set_xlabel("Wavenumber, ν̃ / cm⁻¹")
+spectrum_axis.set_ylabel("|Ĉ(ν̃)| / a.u.")
spectrum_axis.set_xlim(0.0, 4000.0)
spectrum_axis.set_ylim(bottom=0.0)
-figure.tight_layout()
+figure.tight_layout(h_pad=1.4)
plt.show()
diff --git a/docs/source/analyses/index.rst b/docs/source/analyses/index.rst
index 481e54e8..6985cfde 100644
--- a/docs/source/analyses/index.rst
+++ b/docs/source/analyses/index.rst
@@ -25,7 +25,7 @@ Choose by input data
- :math:`\langle |\mathbf{r}(t)-\mathbf{r}(0)|^2\rangle`
* - VACF
- Velocities and frame time step
- - Normalized :math:`C_v(t)` and its spectrum
+ - Normalized :math:`C_{vv}(t)` and its spectrum
* - Vibrations
- Structure, masses and Cartesian Hessian
- Normal-mode wavenumbers and force constants
diff --git a/docs/source/analyses/vacf.rst b/docs/source/analyses/vacf.rst
index 42bcb270..b3662500 100644
--- a/docs/source/analyses/vacf.rst
+++ b/docs/source/analyses/vacf.rst
@@ -6,10 +6,13 @@ velocities lose memory of their initial direction:
.. math::
- C_v(t) =
+ C_{vv}(t) =
\frac{\left\langle \sum_i \mathbf{v}_i(0)\cdot\mathbf{v}_i(t)\right\rangle}
{\left\langle \sum_i \mathbf{v}_i(0)\cdot\mathbf{v}_i(0)\right\rangle}.
+The brackets denote an average over admissible time origins, and the sum runs
+over the selected atoms. This normalization gives :math:`C_{vv}(0)=1`.
+
PQAnalysis can transform the correlation to a wavenumber-domain spectrum. If
static or time-dependent partial charges are supplied, it correlates
:math:`q_i\mathbf{v}_i` instead, producing a charge-flux spectrum that
diff --git a/docs/source/userGuide/analysisOutputFiles.rst b/docs/source/userGuide/analysisOutputFiles.rst
index 4112a05e..74ff4a8d 100644
--- a/docs/source/userGuide/analysisOutputFiles.rst
+++ b/docs/source/userGuide/analysisOutputFiles.rst
@@ -294,7 +294,7 @@ normalized by their zero-lag value, including charge-weighted correlations.
* - 1
- Wavenumber
- Legacy cosine-transform frequency axis
- - cm\ :sup:`-1`
+ - cm⁻¹
* - 2
- Spectrum amplitude
- Absolute cosine-transform amplitude of the optionally windowed
From dae0584488a0c998a8a4c5bc9534c6c2ec2c0c9f Mon Sep 17 00:00:00 2001
From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com>
Date: Fri, 7 Aug 2026 14:41:02 +0200
Subject: [PATCH 5/7] docs: fix compact layout and prose
---
README.md | 11 ++++++++---
docs/source/_plots/vacf.py | 4 ++--
docs/source/_static/css/custom.css | 6 ++++++
docs/source/data/index.rst | 2 +-
docs/source/developerGuide/developerGuide.rst | 6 +++---
docs/source/index.rst | 12 ++++++------
docs/source/reference/api.rst | 4 ++--
docs/source/reference/functions.rst | 8 ++++----
docs/source/userGuide/userGuide.rst | 3 ++-
9 files changed, 34 insertions(+), 22 deletions(-)
diff --git a/README.md b/README.md
index 20965f3b..ea014b9a 100644
--- a/README.md
+++ b/README.md
@@ -7,9 +7,14 @@
[](https://codecov.io/gh/MolarVerse/PQAnalysis)
[](https://opensource.org/licenses/MIT)
-The main purpose of this package is to provide useful tools for the analysis of the Molecular Dynamics software package [PQ](https://github.com/MolarVerse/PQ). Furthermore, the intent of this package is to enable straightforward implementations of newly developed analysis tools on top of the provided API.
-
-The future development of this package focuses on two main goals. On the one hand the enhancement of the provided analysis tools and extending its API to be compatible with many other different Molecular Dynamics engines. As this project is only a *hobby* project of the maintainers, any contributions considering enhancement or bug fixes are highly welcomed.
+PQAnalysis reads structures, trajectories, velocities and Hessians produced by
+[PQ](https://github.com/MolarVerse/PQ). Its command-line and Python interfaces
+share parsers, numerical kernels and schema-defined outputs for RDF, MSD, VACF,
+vibrational, spectral and momentum analyses.
+
+Development focuses on validated analysis methods and support for additional
+molecular-dynamics engines. The maintainers develop PQAnalysis in their free
+time; focused analysis contributions and bug fixes are welcome.
## Installation
diff --git a/docs/source/_plots/vacf.py b/docs/source/_plots/vacf.py
index 8bbd64f8..4bb86c76 100644
--- a/docs/source/_plots/vacf.py
+++ b/docs/source/_plots/vacf.py
@@ -35,7 +35,7 @@
"(a) Normalized velocity autocorrelation",
loc="left",
fontsize=9.5,
- fontweight="semibold",
+ fontweight="bold",
pad=8,
)
correlation_axis.set_xlabel("Lag time, t / ps")
@@ -52,7 +52,7 @@
"(b) Hann-window cosine-transform spectrum",
loc="left",
fontsize=9.5,
- fontweight="semibold",
+ fontweight="bold",
pad=8,
)
spectrum_axis.set_xlabel("Wavenumber, ν̃ / cm⁻¹")
diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css
index 1f65228e..0424044f 100644
--- a/docs/source/_static/css/custom.css
+++ b/docs/source/_static/css/custom.css
@@ -56,6 +56,12 @@ img.plot-directive + figcaption {
overflow-x: auto;
}
+@media (max-width: 44rem), (max-height: 32rem) {
+ .back-to-top {
+ display: none;
+ }
+}
+
@media (max-width: 44rem) {
article table.autosummary,
article table.pq-record-table {
diff --git a/docs/source/data/index.rst b/docs/source/data/index.rst
index f6a2c24b..9b5535e5 100644
--- a/docs/source/data/index.rst
+++ b/docs/source/data/index.rst
@@ -5,7 +5,7 @@ PQAnalysis separates simulation data, analysis configuration and output-table
serialization. File extensions select output formats, while input content and
explicit engine options determine how trajectories are read.
-This section covers four interfaces:
+Four file contracts govern analysis workflows:
* :ref:`inputFile` defines the key-value grammar.
* :ref:`analysisOutputFiles` defines table fields, symbols and units.
diff --git a/docs/source/developerGuide/developerGuide.rst b/docs/source/developerGuide/developerGuide.rst
index 0dee40ba..2e96bb0a 100644
--- a/docs/source/developerGuide/developerGuide.rst
+++ b/docs/source/developerGuide/developerGuide.rst
@@ -3,9 +3,9 @@
Development
===========
-PQAnalysis uses a ``dev`` integration branch and releases from ``main``. This
-section documents the code boundaries and evidence required to extend the
-package, not only the mechanics of opening a pull request.
+PQAnalysis integrates changes on ``dev`` and releases from ``main``. The guides
+define package boundaries, implementation contracts, validation evidence and
+release operations.
Extension path
--------------
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 9f8c4da0..24885938 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -66,18 +66,18 @@ scientific kernels as the command line:
rdf("rdf.in", export_files=["rdf.csv"])
table = read_analysis_table("rdf.csv")
-The :doc:`function index ` exposes analysis workflows,
-numerical methods, scientific-table operations and simulation-file I/O without
-requiring navigation through the generated module tree.
+The :doc:`function index ` groups analysis workflows,
+numerical methods, scientific-table operations and simulation-file I/O by
+task.
Development
-----------
New methods follow a documented path from estimator and validation evidence to
the public API, CLI and schema-backed output. See
-:doc:`Adding an Analysis ` for the complete
-implementation checklist and :doc:`Architecture `
-for package ownership boundaries.
+:doc:`Adding an Analysis ` for the required
+implementation steps and :doc:`Architecture ` for
+package ownership boundaries.
.. toctree::
:hidden:
diff --git a/docs/source/reference/api.rst b/docs/source/reference/api.rst
index fd5c00ce..d5f81ec9 100644
--- a/docs/source/reference/api.rst
+++ b/docs/source/reference/api.rst
@@ -1,8 +1,8 @@
Package Reference
=================
-Start with the :doc:`functions` page for callable analysis, numerical and I/O
-interfaces. This page maps the principal data types and generated module
+The :doc:`functions` page documents callable analysis, numerical and I/O
+interfaces. The tables below map principal data types to the generated module
reference.
Core types
diff --git a/docs/source/reference/functions.rst b/docs/source/reference/functions.rst
index 73645e48..00d6e8da 100644
--- a/docs/source/reference/functions.rst
+++ b/docs/source/reference/functions.rst
@@ -3,10 +3,10 @@
Function Index
==============
-This page lists the callable Python interfaces intended for direct use. The
-analysis wrappers accept the same input files as their command-line
-counterparts. Lower-level numerical functions operate on arrays or PQAnalysis
-objects and do not parse command-line arguments.
+Callable Python interfaces are grouped below by task. Analysis wrappers accept
+the same input files as their command-line counterparts. Lower-level numerical
+functions operate on arrays or PQAnalysis objects and do not parse command-line
+arguments.
Analysis workflows
------------------
diff --git a/docs/source/userGuide/userGuide.rst b/docs/source/userGuide/userGuide.rst
index d826ab05..bfec87c7 100644
--- a/docs/source/userGuide/userGuide.rst
+++ b/docs/source/userGuide/userGuide.rst
@@ -5,7 +5,8 @@
User Guide
==========
-This compatibility page points to the current task-oriented documentation:
+The former user-guide URL is retained for compatibility. Current documentation
+is organized by task:
* :doc:`../getting-started`: installation, first RDF calculation and outputs
* :doc:`../analyses/index`: estimators, assumptions and interpretation
From 40ba2b90087c9ceb6728f2cd3533e2b769fd9655 Mon Sep 17 00:00:00 2001
From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com>
Date: Fri, 7 Aug 2026 15:05:48 +0200
Subject: [PATCH 6/7] docs: use representative VACF model
---
docs/source/_plots/vacf.py | 48 +++++++++++++++++++++++------------
docs/source/analyses/vacf.rst | 10 +++++---
2 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/docs/source/_plots/vacf.py b/docs/source/_plots/vacf.py
index 4bb86c76..52c11b83 100644
--- a/docs/source/_plots/vacf.py
+++ b/docs/source/_plots/vacf.py
@@ -1,18 +1,34 @@
-"""VACF and Hann-window spectrum from the validation fixture."""
+"""Analytical damped VACF and its PQAnalysis spectrum."""
import matplotlib.pyplot as plt
import numpy as np
-from _style import COLORS, PROJECT_ROOT, apply_style
+from PQAnalysis.analysis.vacf.spectrum import vacf_spectrum
+
+from _style import COLORS, apply_style
apply_style((6.2, 5.5))
-correlation = np.loadtxt(PROJECT_ROOT / "tests/data/vacf/vacf_ref.dat")
-spectrum = np.loadtxt(
- PROJECT_ROOT / "tests/data/vacf/spectrum_hann_ref.dat"
+time = np.arange(0.0, 0.3005, 0.0005)
+correlation = (
+ 0.85 * np.exp(-(time / 0.075) ** 2)
+ * np.cos(2.0 * np.pi * 9.0 * time)
+ + 0.15 * np.exp(-(time / 0.035) ** 2)
+ * np.cos(2.0 * np.pi * 42.0 * time)
+)
+
+wavenumbers, amplitudes, _ = vacf_spectrum(
+ time,
+ correlation,
+ ftsize=4096,
+ window_function="hann",
+ window_stop=float(time[-1]),
)
-spectrum = spectrum[spectrum[:, 0] <= 4000.0]
+display_range = wavenumbers <= 4000.0
+wavenumbers = wavenumbers[display_range]
+amplitudes = amplitudes[display_range]
+amplitudes /= amplitudes.max()
figure, (correlation_axis, spectrum_axis) = plt.subplots(
2,
@@ -21,8 +37,8 @@
)
correlation_axis.plot(
- correlation[:, 0],
- correlation[:, 1],
+ time,
+ correlation,
color=COLORS["blue"],
)
correlation_axis.axhline(
@@ -32,7 +48,7 @@
linewidth=1.0,
)
correlation_axis.set_title(
- "(a) Normalized velocity autocorrelation",
+ "(a) Normalized damped VACF",
loc="left",
fontsize=9.5,
fontweight="bold",
@@ -40,25 +56,25 @@
)
correlation_axis.set_xlabel("Lag time, t / ps")
correlation_axis.set_ylabel("Cᵥᵥ(t)")
-correlation_axis.set_xlim(correlation[0, 0], correlation[-1, 0])
-correlation_axis.set_ylim(-1.05, 1.05)
+correlation_axis.set_xlim(time[0], time[-1])
+correlation_axis.set_ylim(-0.65, 1.05)
spectrum_axis.plot(
- spectrum[:, 0],
- spectrum[:, 1],
+ wavenumbers,
+ amplitudes,
color=COLORS["orange"],
)
spectrum_axis.set_title(
- "(b) Hann-window cosine-transform spectrum",
+ "(b) Hann-window spectrum",
loc="left",
fontsize=9.5,
fontweight="bold",
pad=8,
)
spectrum_axis.set_xlabel("Wavenumber, ν̃ / cm⁻¹")
-spectrum_axis.set_ylabel("|Ĉ(ν̃)| / a.u.")
+spectrum_axis.set_ylabel("Relative amplitude")
spectrum_axis.set_xlim(0.0, 4000.0)
-spectrum_axis.set_ylim(bottom=0.0)
+spectrum_axis.set_ylim(0.0, 1.05)
figure.tight_layout(h_pad=1.4)
plt.show()
diff --git a/docs/source/analyses/vacf.rst b/docs/source/analyses/vacf.rst
index b3662500..e39b34b5 100644
--- a/docs/source/analyses/vacf.rst
+++ b/docs/source/analyses/vacf.rst
@@ -22,10 +22,12 @@ Correlation and spectrum
------------------------
.. plot:: _plots/vacf.py
- :alt: Velocity autocorrelation function and its Hann-window spectrum
- :caption: Bundled VACF validation fixture and its Hann-window cosine
- transform. Spectrum amplitudes are reported in arbitrary units; the
- displayed range is limited to 4000 cm⁻¹.
+ :alt: Analytical normalized VACF with a negative correlation lobe and its
+ Hann-window spectrum
+ :caption: Analytical two-mode VACF and its PQAnalysis Hann-window cosine
+ transform. The 300 and 1400 cm⁻¹ modes use Gaussian decay times of
+ 0.075 and 0.035 ps, respectively. The correlation and spectrum are
+ normalized to unit maxima.
Minimal input
-------------
From 05ea674dea3cac55b67259678aabf374abdc0edb Mon Sep 17 00:00:00 2001
From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com>
Date: Fri, 7 Aug 2026 22:21:12 +0200
Subject: [PATCH 7/7] docs: clarify VACF apodization
---
docs/source/_plots/vacf.py | 36 +++++++++++++++----------
docs/source/analyses/vacf.rst | 49 +++++++++++++++++++++++------------
2 files changed, 56 insertions(+), 29 deletions(-)
diff --git a/docs/source/_plots/vacf.py b/docs/source/_plots/vacf.py
index 52c11b83..b60a9891 100644
--- a/docs/source/_plots/vacf.py
+++ b/docs/source/_plots/vacf.py
@@ -1,4 +1,4 @@
-"""Analytical damped VACF and its PQAnalysis spectrum."""
+"""Analytical two-band VACF and its PQAnalysis spectrum."""
import matplotlib.pyplot as plt
import numpy as np
@@ -10,22 +10,22 @@
apply_style((6.2, 5.5))
-time = np.arange(0.0, 0.3005, 0.0005)
+time = np.arange(0.0, 0.5005, 0.0005)
correlation = (
- 0.85 * np.exp(-(time / 0.075) ** 2)
+ 0.70 * np.exp(-(time / 0.22) ** 2)
* np.cos(2.0 * np.pi * 9.0 * time)
- + 0.15 * np.exp(-(time / 0.035) ** 2)
- * np.cos(2.0 * np.pi * 42.0 * time)
+ + 0.30 * np.exp(-(time / 0.12) ** 2)
+ * np.cos(2.0 * np.pi * 18.0 * time)
)
-wavenumbers, amplitudes, _ = vacf_spectrum(
+wavenumbers, amplitudes, windowed_correlation = vacf_spectrum(
time,
correlation,
- ftsize=4096,
- window_function="hann",
- window_stop=float(time[-1]),
+ ftsize=5000,
+ window_function="exponential",
+ window_param=4.0,
)
-display_range = wavenumbers <= 4000.0
+display_range = wavenumbers <= 1000.0
wavenumbers = wavenumbers[display_range]
amplitudes = amplitudes[display_range]
amplitudes /= amplitudes.max()
@@ -40,6 +40,15 @@
time,
correlation,
color=COLORS["blue"],
+ label="Unwindowed",
+)
+correlation_axis.plot(
+ time,
+ windowed_correlation,
+ color=COLORS["green"],
+ linestyle="--",
+ linewidth=1.6,
+ label="Exponential, 4 ps⁻¹",
)
correlation_axis.axhline(
0.0,
@@ -48,7 +57,7 @@
linewidth=1.0,
)
correlation_axis.set_title(
- "(a) Normalized damped VACF",
+ "(a) Normalized VACF",
loc="left",
fontsize=9.5,
fontweight="bold",
@@ -58,6 +67,7 @@
correlation_axis.set_ylabel("Cᵥᵥ(t)")
correlation_axis.set_xlim(time[0], time[-1])
correlation_axis.set_ylim(-0.65, 1.05)
+correlation_axis.legend(loc="upper right")
spectrum_axis.plot(
wavenumbers,
@@ -65,7 +75,7 @@
color=COLORS["orange"],
)
spectrum_axis.set_title(
- "(b) Hann-window spectrum",
+ "(b) Exponential-window spectrum",
loc="left",
fontsize=9.5,
fontweight="bold",
@@ -73,7 +83,7 @@
)
spectrum_axis.set_xlabel("Wavenumber, ν̃ / cm⁻¹")
spectrum_axis.set_ylabel("Relative amplitude")
-spectrum_axis.set_xlim(0.0, 4000.0)
+spectrum_axis.set_xlim(0.0, 1000.0)
spectrum_axis.set_ylim(0.0, 1.05)
figure.tight_layout(h_pad=1.4)
diff --git a/docs/source/analyses/vacf.rst b/docs/source/analyses/vacf.rst
index e39b34b5..8f8d5cd4 100644
--- a/docs/source/analyses/vacf.rst
+++ b/docs/source/analyses/vacf.rst
@@ -7,27 +7,36 @@ velocities lose memory of their initial direction:
.. math::
C_{vv}(t) =
- \frac{\left\langle \sum_i \mathbf{v}_i(0)\cdot\mathbf{v}_i(t)\right\rangle}
- {\left\langle \sum_i \mathbf{v}_i(0)\cdot\mathbf{v}_i(0)\right\rangle}.
+ \left\langle
+ \frac{\sum_i \mathbf{v}_i(t_0)\cdot\mathbf{v}_i(t_0+t)}
+ {\sum_i \mathbf{v}_i(t_0)\cdot\mathbf{v}_i(t_0)}
+ \right\rangle_{t_0}.
The brackets denote an average over admissible time origins, and the sum runs
-over the selected atoms. This normalization gives :math:`C_{vv}(0)=1`.
+over the selected atoms. This is the default, legacy-compatible estimator and
+gives :math:`C_{vv}(0)=1`. The ``fft`` estimator instead averages the numerator
+and denominator separately over all available origins before normalization.
PQAnalysis can transform the correlation to a wavenumber-domain spectrum. If
static or time-dependent partial charges are supplied, it correlates
:math:`q_i\mathbf{v}_i` instead, producing a charge-flux spectrum that
approximates an infrared spectrum.
+The correlation written to ``out_file`` is not apodized. When a spectrum is
+requested, ``window_function`` multiplies a copy of the correlation before the
+cosine transform. The optional ``windowed_out_file`` records that copy.
+
Correlation and spectrum
------------------------
.. plot:: _plots/vacf.py
- :alt: Analytical normalized VACF with a negative correlation lobe and its
- Hann-window spectrum
- :caption: Analytical two-mode VACF and its PQAnalysis Hann-window cosine
- transform. The 300 and 1400 cm⁻¹ modes use Gaussian decay times of
- 0.075 and 0.035 ps, respectively. The correlation and spectrum are
- normalized to unit maxima.
+ :alt: Analytical normalized VACF, its exponentially windowed copy and the
+ resulting spectrum
+ :caption: Analytical normalized VACF for two Gaussian-broadened bands
+ centered at 300 and 600 cm⁻¹, with dephasing times of 0.22 and 0.12 ps.
+ The dashed curve applies an exponential window with a decay coefficient
+ of 4 ps⁻¹ before the PQAnalysis cosine transform. Spectrum amplitudes
+ are scaled to unit maximum.
Minimal input
-------------
@@ -49,18 +58,26 @@ Minimal input
$ pqanalysis vacf vacf.in
-The time step is specified in ps. ``window_function`` accepts
-``exponential``, ``hann`` and ``blackman``. The default sliding-origin method
-matches the legacy calculation; ``method = fft`` selects a denser-origin
-Wiener-Khinchin estimator.
+The time step is specified in ps. ``window`` is the maximum correlation lag in
+frames; it is distinct from the apodization selected by ``window_function``.
+The example multiplies only the spectrum input by
+:math:`\exp[-(4\ \mathrm{ps}^{-1})t]`. ``window_function`` also accepts
+``hann``, ``blackman`` and ``none``; ``none`` is the default. The default
+sliding-origin method matches the legacy calculation. ``gap`` controls the
+spacing between its time origins, not the lag-time spacing in ``out_file``;
+``method = fft`` selects a denser-origin Wiener-Khinchin estimator.
Interpretation
--------------
* A rapidly decaying VACF indicates fast velocity decorrelation.
-* Negative regions indicate backscattering or cage motion.
-* The frequency spectrum depends on the sampling interval, correlation length,
- apodization window and zero-padding size.
+* In liquids, negative regions often indicate backscattering or cage motion;
+ in solids, sign oscillations reflect bound vibrational motion.
+* The sampling interval sets the Nyquist limit, and the correlation length sets
+ the resolving power. Zero-padding provides a denser frequency grid but does
+ not add spectral resolution.
+* Apodization reduces endpoint artifacts but changes band widths and
+ amplitudes; report the selected function and its parameters.
* Charge-flux spectra require physically meaningful partial charges and should
not be interpreted as absolute IR intensities without further calibration.