Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,37 @@ jobs:
build/test_artifacts/**/*.jpeg
if-no-files-found: warn

docs:
name: Build Sphinx docs
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install docs dependencies
run: |
python -m pip install --upgrade pip
python -m pip install sphinx sphinx-rtd-theme scipy numpy

- name: Build docs
run: |
cd docs && sphinx-build -b html . _build/html

- name: Upload docs artifact
uses: actions/upload-artifact@v4
with:
name: docs-html
path: docs/_build/html

dashboard:
name: Build test dashboard
needs: GNU
needs: [GNU, docs]
if: ${{ needs.GNU.result == 'success' }}
runs-on: ubuntu-latest
permissions:
Expand Down Expand Up @@ -243,14 +271,33 @@ jobs:

rm -f "$tmp_json"

- name: Download docs artifact
uses: actions/download-artifact@v4
with:
name: docs-html
path: docs-html

- name: Merge docs with dashboard
run: |
set -euo pipefail
mkdir -p site
if [ -d dashboard/test ]; then
mv dashboard/test site/test
else
mkdir -p site/test
fi
cp -r docs-html/* site/
echo "Site structure:"
find site -type f | head -20 || true

- name: Configure Pages
if: ${{ github.event_name == 'push' }}
uses: actions/configure-pages@v5

- name: Upload dashboard artifact
- name: Upload pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: './dashboard'
path: './site'

deploy:
name: Deploy to GitHub Pages
Expand Down
1 change: 1 addition & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_build/
14 changes: 14 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Minimal makefile for Sphinx documentation

SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
26 changes: 26 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
API Reference
=============

EQDSK Module
------------

.. automodule:: libneo.eqdsk
:members:
:undoc-members:
:show-inheritance:

Flux Converter Module
---------------------

.. automodule:: libneo.flux_converter
:members:
:undoc-members:
:show-inheritance:

VMEC Module
-----------

.. automodule:: libneo.vmec
:members:
:undoc-members:
:show-inheritance:
38 changes: 38 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Sphinx configuration for libneo documentation."""

import os
import sys

sys.path.insert(0, os.path.abspath('../python'))

project = 'libneo'
copyright = '2024, ITPcp'
author = 'ITPcp'

extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.viewcode',
'sphinx.ext.intersphinx',
]

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']

autodoc_default_options = {
'members': True,
'undoc-members': True,
'show-inheritance': True,
}

napoleon_google_docstring = False
napoleon_numpy_docstring = True

intersphinx_mapping = {
'python': ('https://docs.python.org/3', None),
'numpy': ('https://numpy.org/doc/stable/', None),
'scipy': ('https://docs.scipy.org/doc/scipy/', None),
}
143 changes: 143 additions & 0 deletions docs/eqdsk.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
EQDSK Equilibrium Files
=======================

The ``eqdsk_file`` class provides tools for reading G-EQDSK equilibrium files
and converting between cylindrical (R, Z) coordinates and flux coordinates.

Reading EQDSK Files
-------------------

.. code-block:: python

from libneo import eqdsk_file

eq = eqdsk_file('equilibrium.geqdsk')

# Access grid data
print(f"R range: {eq.R.min():.2f} - {eq.R.max():.2f} m")
print(f"Z range: {eq.Z.min():.2f} - {eq.Z.max():.2f} m")
print(f"Magnetic axis: R={eq.Rpsi0:.3f} m, Z={eq.Zpsi0:.3f} m")

Coordinate Conversion
---------------------

Converting (R, Z) to Flux Coordinates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The most common use case is converting arbitrary (R, Z) measurement points
to normalized poloidal flux coordinates for radial profile analysis:

.. code-block:: python

import numpy as np
from libneo import eqdsk_file

eq = eqdsk_file('equilibrium.geqdsk')

# Single point
R, Z = 1.8, 0.1
s_pol, theta = eq.rz_to_flux_coords(R, Z)
print(f"s_pol = {s_pol:.3f}, theta = {theta:.3f} rad")

# Array of measurement points
R_data = np.array([1.7, 1.8, 1.9, 2.0])
Z_data = np.array([0.0, 0.1, -0.1, 0.0])
s_pol, theta = eq.rz_to_flux_coords(R_data, Z_data)

Interpolating Poloidal Flux
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Get the raw poloidal flux values at arbitrary (R, Z) points:

.. code-block:: python

# Scalar
psi = eq.psi_at_rz(1.8, 0.1)

# Vectorized
psi = eq.psi_at_rz(R_data, Z_data)

# On a 2D grid (for contour plots)
R_grid = np.linspace(1.5, 2.2, 50)
Z_grid = np.linspace(-0.5, 0.5, 50)
psi_2d = eq.psi_at_rz(R_grid, Z_grid, grid=True)

Plotting Scalar Data vs Flux Coordinate
---------------------------------------

A typical workflow for plotting diagnostic data against normalized flux:

.. code-block:: python

import numpy as np
import matplotlib.pyplot as plt
from libneo import eqdsk_file

# Load equilibrium
eq = eqdsk_file('equilibrium.geqdsk')

# Your measurement data at (R, Z) locations
R_meas = np.array([1.65, 1.70, 1.75, 1.80, 1.85, 1.90])
Z_meas = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
temperature = np.array([3.2, 2.8, 2.3, 1.7, 1.1, 0.5]) # keV

# Convert to flux coordinates
s_pol, theta = eq.rz_to_flux_coords(R_meas, Z_meas)
rho_pol = np.sqrt(s_pol) # sqrt(s_pol) is common radial coordinate

# Plot
plt.figure()
plt.plot(rho_pol, temperature, 'o-')
plt.xlabel(r'$\\rho_{pol}$')
plt.ylabel('Temperature [keV]')
plt.title('Temperature Profile')
plt.show()

Flux Coordinate Definitions
---------------------------

Normalized Poloidal Flux (s_pol)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The normalized poloidal flux is defined as:

.. math::

s_{pol} = \\frac{\\psi - \\psi_{axis}}{\\psi_{edge} - \\psi_{axis}}

where:

- :math:`s_{pol} = 0` at the magnetic axis
- :math:`s_{pol} = 1` at the last closed flux surface (LCFS/separatrix)

Geometric Poloidal Angle (theta)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The geometric poloidal angle is defined as:

.. math::

\\theta = \\arctan2(Z - Z_{axis}, R - R_{axis})

where:

- :math:`\\theta = 0` at the outboard midplane (low-field side)
- :math:`\\theta = \\pi/2` at the top
- :math:`\\theta = -\\pi/2` at the bottom
- :math:`\\theta = \\pm\\pi` at the inboard midplane (high-field side)

COCOS Conventions
-----------------

EQDSK files from different sources may use different coordinate conventions
(COCOS). The ``eqdsk_file`` class automatically detects sign inconsistencies
between the header values and the 2D psi array, ensuring that ``spol_at_rz``
always returns 0 at the axis and 1 at the LCFS regardless of the input file
convention.

API Reference
-------------

.. autoclass:: libneo.eqdsk.eqdsk_file
:members: psi_at_rz, spol_at_rz, theta_geometric_at_rz, rz_to_flux_coords
:show-inheritance:
27 changes: 27 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
libneo Documentation
====================

libneo is a Fortran library with Python bindings for plasma physics calculations,
particularly for magnetic field representations, transport calculations, and
coordinate transformations in fusion plasmas.

.. toctree::
:maxdepth: 2
:caption: Contents:

installation
eqdsk
api

Links
=====

* `Test Dashboard <test/index.html>`_ - Visual test results and artifacts
* `GitHub Repository <https://github.com/itpplasma/libneo>`_

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
24 changes: 24 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Installation
============

Requirements
------------

- Python 3.9+
- NumPy
- SciPy (for interpolation features)

Installation
------------

Install from source:

.. code-block:: bash

pip install -e .

For development with all optional dependencies:

.. code-block:: bash

pip install -e ".[dev]"
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ dev = [
"pytest",
"map2disc @ git+https://gitlab.mpcdf.mpg.de/gvec-group/map2disc.git",
]
docs = [
"sphinx",
"sphinx-rtd-theme",
"scipy",
]

[project.scripts]
libneo-write-chartmap = "libneo.chartmap_cli:main"
Expand Down
Loading