The Open FUSION Toolkit (OFT) is a scientific computing suite for plasma and fusion research. It provides finite element methods on unstructured 2D/3D meshes for MHD equilibrium, stability, and time-dependent simulations.
The codebase is a hybrid Fortran/C/C++/Python project:
- Core computational code: Fortran 90 (
.F90files) with C/C++ bridge files - Python interface:
ctypes-based wrappers calling into compiled Fortran shared libraries - Build system: CMake (requires ≥ 3.27), orchestrated by
src/utilities/build_libs.py
| Tool | Purpose | Key Fortran Source | Python Module |
|---|---|---|---|
| TokaMaker | Axisymmetric Grad-Shafranov MHD equilibria | src/physics/grad_shaf*.F90 |
OpenFUSIONToolkit.TokaMaker |
| ThinCurr | Thin-wall eddy current modeling | src/physics/thin_wall*.F90 |
OpenFUSIONToolkit.ThinCurr |
| Marklin | 3D force-free ideal MHD equilibria | src/physics/taylor.F90 |
OpenFUSIONToolkit.Marklin |
| MUG | Time-dependent extended MHD | src/physics/xmhd*.F90 |
(Fortran executables only) |
src/
├── base/ # Core runtime (I/O, XML, sorting, stitching)
├── grid/ # Mesh types, readers (Cubit, Gmsh, native, T3D), multigrid
├── fem/ # Finite element basis functions and operators (H1, Hcurl, Lagrange)
├── lin_alg/ # Linear algebra (native solvers, PETSc, ARPACK, SuperLU, UMFPACK)
├── physics/ # Physics modules (Grad-Shafranov, thin-wall, Taylor, xMHD, tracing)
├── bin/ # Standalone Fortran executables
├── python/
│ ├── OpenFUSIONToolkit/ # Python package (ctypes wrappers)
│ │ ├── TokaMaker/ # TokaMaker Python API
│ │ ├── ThinCurr/ # ThinCurr Python API
│ │ └── Marklin/ # Marklin Python API
│ └── wrappers/ # Fortran-side C-interop wrapper subroutines
├── ext_libs/ # Bundled 3rd-party sources (triangle, minpack, bvls, dlsode)
├── tests/ # Regression tests (pytest-driven, Fortran + Python)
├── examples/ # Jupyter notebook examples per tool
├── utilities/ # Build scripts, code generators, helper tools
├── docs/ # Doxygen documentation sources
├── cmake/ # CMake find-modules for external dependencies
├── include/ # C/Fortran header files
└── CMakeLists.txt # Top-level CMake configuration
OFT uses a two-stage build process:
mkdir builds && cd builds
source ../setup_env.sh # activates Python venv
python ../src/utilities/build_libs.py \
--nthread=4 --build_umfpack=1 --build_superlu=1 \
--build_arpack=1 --oft_build_tests=1 --build_mpich=1This downloads and compiles dependencies (OpenBLAS, HDF5, METIS, etc.) and generates config_cmake.sh — a shell script containing the full CMake invocation with all paths.
# Still in builds/
bash config_cmake.sh # runs cmake, creates builds/build_release/
cd build_release
make # compile
make install # install to builds/install_release/OFT_BUILD_TESTS— build test executables (enable with--oft_build_tests=1)OFT_BUILD_PYTHON— build Python wrappers (default ON)OFT_USE_MPI— enable MPI parallelism (set by--build_mpich=1or--build_openmpi=1)OFT_BUILD_DOCS— build Doxygen documentationOFT_BUILD_EXAMPLES— build example programs
- The project uses a Python virtual environment at
oft_venv/. Alwayssource setup_env.shbefore running builds or tests. - The
copilot-setup-steps.ymlworkflow mirrors the Ubuntu 24.04 GCC 14 + OpenMP CI configuration and pre-builds external libraries in a cachedbuilds/directory. After this workflow runs, the agent environment has:- Compilers:
gcc-14,g++-14,gfortran-14 - Python venv with:
pytest,numpy,scipy,h5py,netcdf4,matplotlib - Pre-built external libraries in
builds/ - OFT compiled and installed in
builds/install_release/
- Compilers:
Python packaging is handled by a dedicated script template at src/python/make_package.sh.in and associated src/python/pyproject.toml.in, which are configured/installed during the CMAKE build process if the OFT_PACKAGE_PYTHON option is set. Dependencies, scripts, and other information are available in this file a supersede the lint-only file src/python/pyproject.toml.
Tests use pytest and are organized under src/tests/ in subdirectories matching the source layout: base/, grid/, lin_alg/, fem/, physics/.
Each test subdirectory has:
test_*.py— pytest test filestest_*.F90— corresponding Fortran test programs (compiled during build)- Various data files (
.h5,.g,.inp, etc.)
From builds/build_release/:
source ../../setup_env.sh
make test # runs: pytest -m "not slow" base grid lin_alg fem physics
make test_full # runs all tests including slow ones
make test_examples # runs example notebook testsOr run individual test files:
cd builds/build_release/tests
../../run_test.sh physics/test_TokaMaker.py -k "test_name"To list tests for a specific file or folder:
cd builds/build_release/tests
../../run_test.sh physics/test_TokaMaker.py --collect-onlyTo run a specific test test_name, optionally with arguments (test_args), within a specific file test_file.py (current working director must contain test_file.py):
python -c "from test_file import test_name; test_name(*test_args)"- Tests marked
@pytest.mark.sloware excluded from default CI runs - Tests marked
@pytest.mark.mpirequire MPI (OFT_HAVE_MPI=1) - Tests marked
@pytest.mark.coverageare for code coverage runs oft_testing.pyprovidesrun_OFT()helper for running Fortran executables with timeout- Physics Python tests (TokaMaker, ThinCurr) use
multiprocessing.Processto isolate OFT runtime (only oneOFT_envinstance per process) - Test timeout is multiplied by 4× when
OFT_DEBUG_TEST=1
Python code is linted with ruff. Configuration is in src/python/pyproject.toml (superseded by src/python/pyproject.toml.in for python packaging):
cd src/python && ruff checkRules: Pyflakes (F) + pycodestyle (E) with ignores for E722, F403, F405. Target: Python 3.7.
A custom lint checks Fortran debug stack entries:
cd src && python utilities/generate_stack.py -lThis validates that all SUBROUTINE/FUNCTION entries have matching debug stack annotations. Run from the src/ directory.
| Workflow | File | Trigger | Purpose |
|---|---|---|---|
| CI Build | ci_build.yaml |
push to main, PRs | Full matrix build (GCC, Intel, macOS) × (OpenMP, MPICH, OpenMPI) |
| Lint | lint.yaml |
push to main, PRs | ruff check + Fortran stack check |
| Coverage | cov_build.yaml |
push to main | Build with --coverage, upload to Codecov |
| CD Build and Deployment | cd_combined.yaml |
push to main, pypi_release, PRs | Release and nightly package/PyPI builds (deploy from pypi_release) |
| Container CD Build and Deployment | container_cd.yaml |
push to main, container_release, PRs | Container release builds (deploy from container_release) |
| GitHub Pages Build | website.yml |
push to main, gh-pages, PRs | Documentation/website build (deploy from gh-pages) |
| Copilot Agent Setup | copilot-setup-steps.yml |
manual/PR | Copilot agent environment setup |
| Copilot Review Setup | copilot-code-review.yml |
manual/PR | Copilot code review agent environment setup |
A representative build environment that can be used for creating a testing sandbox as used in copilot-setup-steps.yml is as follows:
- OS: Ubuntu 24.04
- Compilers:
gcc-14/g++-14/gfortran-14 - Parallel: OpenMP + MPICH (MPI enabled)
- Libraries: OpenBLAS, UMFPACK, SuperLU, ARPACK, HDF5, METIS
- Free-form Fortran 90+ (
.F90extension, preprocessed) - SPDX license header:
! SPDX-License-Identifier: LGPL-3.0-only - Doxygen-style comments with
!>and!!markers - Module names typically prefixed with
oft_(e.g.,oft_gs,oft_la_base) - Line length: unlimited (
-ffree-line-length-none), but keep reasonable - New functions/subroutines must have Doxygen documentation
- All fortran keywords, statements, and built-in functions should be in UPPERCASE
- New functions should use
RESULTstyle definition instead of leading variable style INTEGERandREALdefinitions should explicitly provide theKIND/precision using one ofi4/i8orr4/r8(defined insrc/base/local.F90) respectively- Two space indentation should be used, with the exception of subroutine/function bodies
- SPDX license header comment block at top of each file
- New functions/subroutines must have Doxygen documentation using docstrings with
@-style commands (eg.@param,@result) - Target Python 3.7+ (for OMFIT compatibility)
- Use
ctypesfor Fortran interop; wrapper patterns in_interface.pyfiles - All Python wrappers live under
src/python/OpenFUSIONToolkit/ - Balance readability and efficiency; For example, avoid overly long or nested list comprehensions and inline if statements
- Four space indentation should be used
- PRs for a specific tool should be titled:
ToolName: description(e.g.,TokaMaker: Fix boundary condition) - Keep changes focused on a single feature; secondary changes should be minimal
- Comment on whether APIs or input files change
- Run regression tests before submitting
-
Single OFT_env instance: The Python
OFT_envclass enforces a singleton. Tests usemultiprocessing.Processto work around this. Never create twoOFT_envinstances in the same process. -
Tests run from build tree: Tests must be run from
builds/build_release/tests/(or viamake testfrombuilds/build_release/), not from the source tree, because compiled Fortran test executables are in the build tree. -
ext_libs/ is bundled third-party code: Do not modify files in
src/ext_libs/. These are upstream sources (triangle, minpack, bvls, dlsode). -
Fortran/Python interop: The Python package calls compiled Fortran via
ctypes. The Fortran-side wrappers are insrc/python/wrappers/and useISO_C_BINDING. Changes to Fortran function signatures require corresponding updates to bothwrappers/*_f.F90andpython/OpenFUSIONToolkit/*/_interface.py. -
CMake template files: Some files use
@VARIABLE@CMake substitution (e.g.,__init__.py,pyproject.toml.in,run_test.sh.in). Edit the.intemplate, not the generated file.