Skip to content

Commit 69a568e

Browse files
authored
1 parent 255fd38 commit 69a568e

2 files changed

Lines changed: 211 additions & 3 deletions

File tree

.github/copilot-instructions.md

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# Copilot Instructions for OpenFUSIONToolkit
2+
3+
## Project Overview
4+
5+
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.
6+
7+
The codebase is a hybrid Fortran/C/C++/Python project:
8+
- **Core computational code**: Fortran 90 (`.F90` files) with C/C++ bridge files
9+
- **Python interface**: `ctypes`-based wrappers calling into compiled Fortran shared libraries
10+
- **Build system**: CMake (requires ≥ 3.27), orchestrated by `src/utilities/build_libs.py`
11+
12+
### Component Tools
13+
14+
| Tool | Purpose | Key Fortran Source | Python Module |
15+
|---|---|---|---|
16+
| **TokaMaker** | Axisymmetric Grad-Shafranov MHD equilibria | `src/physics/grad_shaf*.F90` | `OpenFUSIONToolkit.TokaMaker` |
17+
| **ThinCurr** | Thin-wall eddy current modeling | `src/physics/thin_wall*.F90` | `OpenFUSIONToolkit.ThinCurr` |
18+
| **Marklin** | 3D force-free ideal MHD equilibria | `src/physics/taylor.F90` | `OpenFUSIONToolkit.Marklin` |
19+
| **MUG** | Time-dependent extended MHD | `src/physics/xmhd*.F90` | *(Fortran executables only)* |
20+
21+
## Repository Layout
22+
23+
```
24+
src/
25+
├── base/ # Core runtime (I/O, XML, sorting, stitching)
26+
├── grid/ # Mesh types, readers (Cubit, Gmsh, native, T3D), multigrid
27+
├── fem/ # Finite element basis functions and operators (H1, Hcurl, Lagrange)
28+
├── lin_alg/ # Linear algebra (native solvers, PETSc, ARPACK, SuperLU, UMFPACK)
29+
├── physics/ # Physics modules (Grad-Shafranov, thin-wall, Taylor, xMHD, tracing)
30+
├── bin/ # Standalone Fortran executables
31+
├── python/
32+
│ ├── OpenFUSIONToolkit/ # Python package (ctypes wrappers)
33+
│ │ ├── TokaMaker/ # TokaMaker Python API
34+
│ │ ├── ThinCurr/ # ThinCurr Python API
35+
│ │ └── Marklin/ # Marklin Python API
36+
│ └── wrappers/ # Fortran-side C-interop wrapper subroutines
37+
├── ext_libs/ # Bundled 3rd-party sources (triangle, minpack, bvls, dlsode)
38+
├── tests/ # Regression tests (pytest-driven, Fortran + Python)
39+
├── examples/ # Jupyter notebook examples per tool
40+
├── utilities/ # Build scripts, code generators, helper tools
41+
├── docs/ # Doxygen documentation sources
42+
├── cmake/ # CMake find-modules for external dependencies
43+
├── include/ # C/Fortran header files
44+
└── CMakeLists.txt # Top-level CMake configuration
45+
```
46+
47+
## Build System
48+
49+
OFT uses a two-stage build process:
50+
51+
### Stage 1: Build external libraries
52+
53+
```bash
54+
mkdir builds && cd builds
55+
source ../setup_env.sh # activates Python venv
56+
python ../src/utilities/build_libs.py \
57+
--nthread=4 --build_umfpack=1 --build_superlu=1 \
58+
--build_arpack=1 --oft_build_tests=1 --build_mpich=1
59+
```
60+
61+
This downloads and compiles dependencies (OpenBLAS, HDF5, METIS, etc.) and generates `config_cmake.sh` — a shell script containing the full CMake invocation with all paths.
62+
63+
### Stage 2: Configure, build, and install OFT
64+
65+
```bash
66+
# Still in builds/
67+
bash config_cmake.sh # runs cmake, creates builds/build_release/
68+
cd build_release
69+
make # compile
70+
make install # install to builds/install_release/
71+
```
72+
73+
### Key CMake options (set via build_libs.py flags)
74+
75+
- `OFT_BUILD_TESTS` — build test executables (enable with `--oft_build_tests=1`)
76+
- `OFT_BUILD_PYTHON` — build Python wrappers (default ON)
77+
- `OFT_USE_MPI` — enable MPI parallelism (set by `--build_mpich=1` or `--build_openmpi=1`)
78+
- `OFT_BUILD_DOCS` — build Doxygen documentation
79+
- `OFT_BUILD_EXAMPLES` — build example programs
80+
81+
### Important Environment Notes
82+
83+
- The project uses a Python virtual environment at `oft_venv/`. **Always** `source setup_env.sh` before running builds or tests.
84+
- The `copilot-setup-steps.yml` workflow mirrors the Ubuntu 24.04 GCC 14 + OpenMP CI configuration and pre-builds external libraries in a cached `builds/` directory. After this workflow runs, the agent environment has:
85+
- Compilers: `gcc-14`, `g++-14`, `gfortran-14`
86+
- Python venv with: `pytest`, `numpy`, `scipy`, `h5py`, `matplotlib`, `xarray`
87+
- Pre-built external libraries in `builds/`
88+
- OFT compiled and installed in `builds/install_release/`
89+
90+
## Testing
91+
92+
Tests use **pytest** and are organized under `src/tests/` in subdirectories matching the source layout: `base/`, `grid/`, `lin_alg/`, `fem/`, `physics/`.
93+
94+
### Test structure
95+
96+
Each test subdirectory has:
97+
- `test_*.py` — pytest test files
98+
- `test_*.F90` — corresponding Fortran test programs (compiled during build)
99+
- Various data files (`.h5`, `.g`, `.inp`, etc.)
100+
101+
### Running tests
102+
103+
From `builds/build_release/`:
104+
105+
```bash
106+
source ../../setup_env.sh
107+
make test # runs: pytest -m "not slow" base grid lin_alg fem physics
108+
make test_full # runs all tests including slow ones
109+
make test_examples # runs example notebook tests
110+
```
111+
112+
Or run individual test files:
113+
114+
```bash
115+
cd builds/build_release/tests
116+
../../run_test.sh physics/test_TokaMaker.py -k "test_name"
117+
../../run_test.sh physics/test_TokaMaker.py --collect-only
118+
```
119+
120+
### Test conventions
121+
122+
- Tests marked `@pytest.mark.slow` are excluded from default CI runs
123+
- Tests marked `@pytest.mark.mpi` require MPI (`OFT_HAVE_MPI=1`)
124+
- Tests marked `@pytest.mark.coverage` are for code coverage runs
125+
- `oft_testing.py` provides `run_OFT()` helper for running Fortran executables with timeout
126+
- Physics Python tests (TokaMaker, ThinCurr) use `multiprocessing.Process` to isolate OFT runtime (only one `OFT_env` instance per process)
127+
- Test timeout is multiplied by 4× when `OFT_DEBUG_TEST=1`
128+
129+
## Linting
130+
131+
### Python linting
132+
133+
Python code is linted with **ruff**. Configuration is in `src/python/pyproject.toml`:
134+
135+
```bash
136+
cd src/python && ruff check
137+
```
138+
139+
Rules: Pyflakes (`F`) + pycodestyle (`E`) with ignores for `E722`, `F403`, `F405`. Target: Python 3.7.
140+
141+
### Fortran stack checking
142+
143+
A custom lint checks Fortran debug stack entries:
144+
145+
```bash
146+
cd src && python utilities/generate_stack.py -l
147+
```
148+
149+
This validates that all `SUBROUTINE`/`FUNCTION` entries have matching debug stack annotations. Run from the `src/` directory.
150+
151+
## CI Workflows
152+
153+
| Workflow | File | Trigger | Purpose |
154+
|---|---|---|---|
155+
| **CI Build** | `ci_build.yaml` | push to main, PRs | Full matrix build (GCC, Intel, macOS) × (OpenMP, MPICH, OpenMPI) |
156+
| **Lint** | `lint.yaml` | push to main, PRs | ruff check + Fortran stack check |
157+
| **Coverage** | `cov_build.yaml` | push to main | Build with `--coverage`, upload to Codecov |
158+
| **CD Nightly** | `cd_nightly.yaml` | schedule | Nightly package builds |
159+
| **Copilot Setup** | `copilot-setup-steps.yml` | manual/PR | Agent environment setup |
160+
161+
### CI configuration used in copilot-setup-steps
162+
163+
- **OS**: Ubuntu 24.04
164+
- **Compilers**: `gcc-14` / `g++-14` / `gfortran-14`
165+
- **Parallel**: OpenMP only (no MPI)
166+
- **Libraries**: OpenBLAS, UMFPACK, SuperLU, ARPACK, HDF5, METIS
167+
168+
## Coding Conventions
169+
170+
### Fortran
171+
172+
- Free-form Fortran 90+ (`.F90` extension, preprocessed)
173+
- SPDX license header: `! SPDX-License-Identifier: LGPL-3.0-only`
174+
- Doxygen-style comments with `!>` and `!!` markers
175+
- Module names typically prefixed with `oft_` (e.g., `oft_gs`, `oft_la_base`)
176+
- Line length: unlimited (`-ffree-line-length-none`), but keep reasonable
177+
- New functions/subroutines must have Doxygen documentation
178+
179+
### Python
180+
181+
- SPDX license header comment block at top of each file
182+
- Doxygen-style docstrings with `@param`, `@result`, `@authors`, `@date`
183+
- Target Python 3.7+ (for OMFIT compatibility)
184+
- Use `ctypes` for Fortran interop; wrapper patterns in `_interface.py` files
185+
- All Python wrappers live under `src/python/OpenFUSIONToolkit/`
186+
187+
### Pull Requests
188+
189+
- PRs for a specific tool should be titled: `ToolName: description` (e.g., `TokaMaker: Fix boundary condition`)
190+
- Keep changes focused on a single feature; secondary changes should be minimal
191+
- Comment on whether APIs or input files change
192+
- Run regression tests before submitting
193+
194+
## Common Pitfalls
195+
196+
1. **Single OFT_env instance**: The Python `OFT_env` class enforces a singleton. Tests use `multiprocessing.Process` to work around this. Never create two `OFT_env` instances in the same process.
197+
198+
2. **Source setup_env.sh**: Always source this before any build/test commands. It activates the Python venv. In CI, this file is generated during prerequisites setup.
199+
200+
3. **Build from `builds/` directory**: The `build_libs.py` script must run from the `builds/` directory. It creates `config_cmake.sh` there. CMake then creates `build_release/` and `install_release/` inside `builds/`.
201+
202+
4. **Tests run from build tree**: Tests must be run from `builds/build_release/tests/` (or via `make test` from `builds/build_release/`), not from the source tree, because compiled Fortran test executables are in the build tree.
203+
204+
5. **ext_libs/ is bundled third-party code**: Do not modify files in `src/ext_libs/`. These are upstream sources (triangle, minpack, bvls, dlsode).
205+
206+
6. **Fortran/Python interop**: The Python package calls compiled Fortran via `ctypes`. The Fortran-side wrappers are in `src/python/wrappers/` and use `ISO_C_BINDING`. Changes to Fortran function signatures require corresponding updates to both `wrappers/*_f.F90` and `python/OpenFUSIONToolkit/*/_interface.py`.
207+
208+
7. **CMake template files**: Some files use `@VARIABLE@` CMake substitution (e.g., `__init__.py`, `pyproject.toml.in`, `run_test.sh.in`). Edit the `.in` template, not the generated file.

.github/workflows/copilot-setup-steps.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
python3 -m venv ${{ github.workspace }}/oft_venv
3737
echo "source ${{ github.workspace }}/oft_venv/bin/activate" > ${{ github.workspace }}/setup_env.sh
3838
source ${{ github.workspace }}/setup_env.sh
39-
python -m pip install pytest numpy scipy h5py triangle matplotlib xarray
39+
python -m pip install pytest numpy scipy h5py matplotlib xarray
4040
4141
- name: Check compilers
4242
run: |
@@ -57,14 +57,14 @@ jobs:
5757
if: ${{ steps.cache-ext-libs.outputs.cache-hit != 'true' }}
5858
run: mkdir builds
5959

60-
- name: Build external libraries (OpenMP)
60+
- name: Build external libraries
6161
if: ${{ steps.cache-ext-libs.outputs.cache-hit != 'true' }}
6262
shell: bash
6363
timeout-minutes: 30
6464
working-directory: builds
6565
run: |
6666
source ${{ github.workspace }}/setup_env.sh
67-
python ../src/utilities/build_libs.py --oblas_dynamic_arch --build_umfpack=1 --build_superlu=1 --no_dl_progress --nthread=4 --build_arpack=1 --oft_build_tests=1
67+
python ../src/utilities/build_libs.py --build_umfpack=1 --build_superlu=1 --no_dl_progress --nthread=4 --build_arpack=1 --oft_build_tests=1 --build_mpich=1
6868
6969
- name: Upload library failure log
7070
uses: actions/upload-artifact@v4

0 commit comments

Comments
 (0)