Skip to content
Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

68 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FGPT

License Python Documentation CI

FGPT is a source-to-source transpiler that converts production scientific Fortran code into executable NumPy-based Python, and optionally into JAX/Equinox-compatible modules for GPU-accelerated and differentiable computation. The current state of the project is a proof of concept, which has been tested on large modules of the IPSL land surface model. The project has received support from the AI4PEX project.


Table of Contents

  1. Introduction
  2. Project Structure
  3. Pipeline Overview
  4. Installation
  5. Usage
  6. Testing
  7. Development
  8. License
  9. Authors

Introduction

FGPT was built to modernise large scientific Fortran codebases β€” such as land-surface models β€” without requiring manual rewriting. It operates in three stages:

  1. Isolation : A target Fortran subroutine is extracted from its module, its cross-module dependencies are resolved, and a standalone compilable unit is produced and validated.
  2. Transpilation : The isolated Fortran AST is translated statement-by-statement and expression-by-expression into a structurally equivalent NumPy-based Python class, preserving the original numerical semantics.
  3. JAX conversion : The generated Python class is rewritten into a JAX/Equinox module: loops become lax.scan or vmap, conditionals become lax.cond or jnp.where, and in-place array updates become .at[].set(), enabling XLA compilation and automatic differentiation.

The translation is AST-based throughout. Fortran source is parsed into an fparser AST; Python output is assembled as a ast.Module and unparsed to source β€” never via string manipulation β€” ensuring syntactic correctness and enabling precise, auditable transformations at every stage.


Project Structure

   fgpt/
   β”œβ”€β”€ src/
   β”‚   └── fgpt/
   β”‚       β”œβ”€β”€ __init__.py
   β”‚       β”œβ”€β”€ __main__.py
   β”‚       β”œβ”€β”€ cli.py                     # Command-line interface
   β”‚       β”œβ”€β”€ version.py                 # Package version
   β”‚       β”œβ”€β”€ isolator.py                # Fortran isolation pipeline
   β”‚       β”œβ”€β”€ autodiff.py                # JAX/Tapenade conversion pipeline
   β”‚       β”‚
   β”‚       β”œβ”€β”€ core/
   β”‚       β”‚   β”œβ”€β”€ frontend/
   |       |   |   β”œβ”€β”€ __init__.py
   β”‚       β”‚   β”‚   β”œβ”€β”€ processor.py       # Fortran parser (fparser wrapper)
   β”‚       β”‚   β”‚   β”œβ”€β”€ extractor.py       # Static analysis and metadata extraction
   β”‚       β”‚   β”‚   └── navigator.py       # Cross-module symbol resolution
   β”‚       β”‚   β”‚
   β”‚       β”‚   β”œβ”€β”€ analysis/
   |       |   |   β”œβ”€β”€ __init__.py
   β”‚       β”‚   β”‚   └── shaper.py          # Array shape/dimension analysis
   β”‚       β”‚   β”‚
   β”‚       β”‚   β”œβ”€β”€ passes/
   |       |   |   β”œβ”€β”€ __init__.py
   β”‚       β”‚   β”‚   └── modifier.py        # Fortran AST transformation passes
   β”‚       β”‚   β”‚
   β”‚       β”‚   β”œβ”€β”€ lowering/
   |       |   |   β”œβ”€β”€ __init__.py
   β”‚       β”‚   β”‚   β”œβ”€β”€ transformer.py     # Fortran β†’ Python pipeline
   β”‚       β”‚   β”‚   β”œβ”€β”€ f2np.py            # Statement/expression-level translation
   β”‚       β”‚   β”‚   └── intrinsic.py       # Fortran intrinsic β†’ NumPy mapping
   β”‚       β”‚   β”‚
   β”‚       β”‚   β”œβ”€β”€ backends/
   |       |   |   β”œβ”€β”€ __init__.py
   |       |   |   β”œβ”€β”€ utils.py                  # Shared helper functions used across backend modules
   |       |   |   └── jax_converter/
   |       |   |       β”œβ”€β”€ converter.py          # Main entry point: orchestrates conversion of code into JAX representations
   |       |   |       β”œβ”€β”€ analysis.py           # Static/dynamic analysis utilities (shape inference, dependency tracking, etc.)
   |       |   |       β”œβ”€β”€ array_updates.py      # Handles array mutation patterns and converts them to JAX-safe updates
   |       |   |       β”œβ”€β”€ call_rewriting.py     # Rewrites function calls into JAX-compatible primitives or transformations
   |       |   |       β”œβ”€β”€ conditionals.py       # Transforms if/else logic into JAX control-flow primitives (e.g., lax.cond)
   |       |   |       β”œβ”€β”€ dynamic_loops.py      # Deals with loops whose bounds depend on runtime values (dynamic control flow)
   |       |   |       β”œβ”€β”€ loops.py              # Handles static/structured loop transformations
   |       |   |       β”œβ”€β”€ masking.py            # Implements masking strategies for conditional execution without branching
   |       |   |       β”œβ”€β”€ scope_utils.py        # Utilities for managing variable scope during transformation/rewrite passes
   |       |   |       └── vectorization.py      # Converts scalar functions into vectorized versions
   β”‚       β”‚   └── common/
   |       |       β”œβ”€β”€ __init__.py
   β”‚       β”‚       β”œβ”€β”€ executive.py       # Workflow orchestration
   β”‚       β”‚       β”œβ”€β”€ logger.py          # Logging infrastructure
   β”‚       β”‚       β”œβ”€β”€ line_length.py     # Fortran line-length utilities
   β”‚       β”‚       └── utils.py           # Shared helper utilities
   β”‚       β”‚
   β”‚       └── templates/
   β”‚           └── default.yaml
   β”œβ”€β”€ tests/                    # Unit tests
   β”‚   β”œβ”€β”€ conftest.py
   β”‚   β”œβ”€β”€ test_autodiff.py
   β”‚   β”œβ”€β”€ test_extractor.py
   β”‚   β”œβ”€β”€ test_f2np.py
   β”‚   β”œβ”€β”€ test_intrinsic.py
   β”‚   β”œβ”€β”€ test_jaxconverter.py
   β”‚   β”œβ”€β”€ test_jax_utils.py
   β”‚   β”œβ”€β”€ test_navigator.py
   β”‚   β”œβ”€β”€ test_processor.py
   β”‚   β”œβ”€β”€ test_shaper.py
   β”‚   β”œβ”€β”€ test_utils.py
   β”‚   └── test_transformer.py
   |
   β”œβ”€β”€ notebooks/                         # Example notebooks, tutorials, and development prototypes
   β”‚   β”œβ”€β”€ autodiff_principles.ipynb      # Introduction to JVP and VJP concepts
   β”‚   β”œβ”€β”€ prototype.ipynb                # Experimental notebook with autodifferenciation
   β”‚   β”œβ”€β”€ fortran_to_numpy.ipynb         # F2NP translation examples
   β”‚   β”œβ”€β”€ jax_converter.ipynb            # JAX conversion pipeline examples
   β”‚   └── jax_examples.ipynb             # JAX experiments and demonstrations
   |
   β”œβ”€β”€ docs/                     # Documentation
   β”‚   β”œβ”€β”€ source/
   β”‚   └── build/
   β”œβ”€β”€ .github/workflows/        # CI/CD pipelines
   β”‚   └── ci.yaml
   |
   β”œβ”€β”€ setup                     # Setup file for transformation
   β”œβ”€β”€ arch-nvhpc_HAL.env
   β”œβ”€β”€ arch-nvhpc_LEONARDO.env
   β”œβ”€β”€ arch-nvhpc_spirit.env
   β”œβ”€β”€ Makefile                  # Run isolated procedures
   β”œβ”€β”€ template.yaml             # Code generation templates(user-facing, can be customised freely)
   β”œβ”€β”€ pyproject.toml            # Package configuration
   β”œβ”€β”€ README.md                 # Project README
   └── LICENSE                   # CC BY-NC-SA 4.0

Pipeline Overview

             Fortran Source (.f90)
                     β”‚
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 1 β€” Isolation & Analysis         β”‚
β”‚  Processor β†’ Isolator                   β”‚
β”‚       β”œβ”€β”€ Navigator  ─┐                 β”‚
β”‚       └── Extractor β—„β”€β”˜                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ corrected Fortran AST
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 2 β€” Transpilation                β”‚
β”‚  F2NP β†’ Transformer                     β”‚
β”‚       β”œβ”€β”€ ReplaceGlobals                β”‚
β”‚       └── AdjustIndices                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ .py source file
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 3 β€” JAX Conversion (optional)    β”‚
β”‚  AutoDiff β†’ JaxConverter                β”‚
β”‚       β”œβ”€β”€ lax.scan / vmap               β”‚
β”‚       β”œβ”€β”€ lax.cond / jnp.where          β”‚
β”‚       └── .at[].set()                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                     β–Ό
        JAX/Equinox Module (_jax.py)

Installation

Requirements

  • Python 3.10+
  • A Fortran compiler (e.g. gfortran, nvhpc) accessible on PATH
  • fparser2 for Fortran AST construction

Using pip

git clone https://github.com/kardaneh/IPSL-FGPT.git
cd fgpt
pip install -e .

Using uv (recommended)

# Install uv (via pip or curl)
pip install uv
# or (Linux/macOS)
curl -LsSf https://astral.sh/uv/install.sh | sh
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc

# Clone the repository
git clone https://github.com/kardaneh/IPSL-FGPT.git
cd fgpt

# Create virtual environment and activate
uv venv --python 3.10
source .venv/bin/activate

# Install FGPT in editable mode
uv pip install -e

# Optional: install extra dependencies
uv pip install -e ".[dev]" # development
uv pip install -e ".[notebooks]" # notebooks
uv pip install -e ".[doc]" # documentation(Sphinx)

Usage

Isolating and transpiling a subroutine

from fgpt.isolator import Isolator

isolator = Isolator(
    rest_of_path="modipsl/modeles/ORCHIDEE/src_sechiba/",
    target_module="hydrol",
    work="/scratch/user/runs",
    f2py=True,          # also produce Python output
)

isolator.run(
    parent_subroutine="hydrol_main",
    target_subroutines=["hydrol_soil", "hydrol_alma"],
)

Command-line interface

The CLI exposes two subcommands corresponding to the two stages of the pipeline.

Stage 1 - 3 β€” Isolation, transpilation and JAX conversion

fgpt isolate \
    --rest_of_path modipsl/modeles/ORCHIDEE/src_sechiba/ \
    --target_module hydrol \
    --work /scratch/user/runs \
    --parent_subroutine hydrol_main \
    --target_subroutines hydrol_soil hydrol_alma \
    --f2py True \
    --openacc False \
    --tapenade False \
    --py2jx False \
    --mode jax \
    --config_path template.yaml \
    --vectorize kjpindex \
    --benchmark_dir benchmark/ \

The key flags control which transformation path is taken:

Flag Default Description
--f2py False Also transpile the isolated Fortran to NumPy Python
--openacc False Preserve OpenACC directives for GPU Fortran output
--tapenade False Prepare output for Tapenade automatic differentiation
--py2jx False Prepare output for JAX transformation and optimization

These three flags are mutually independent, except that py2jx requires f2py to be enabled. For example, --f2py True --openacc True produces both a Python translation and an OpenACC-annotated Fortran output.

Stage 3 β€” JAX conversion:

fgpt autodiff \
    --config_path template.yaml \
    --class_file hydrol/hydrol_soil/global_module_hydrol_soil.py \
    --main_file hydrol/hydrol_soil/main_hydrol_soil.py \
    --vectorize kjpindex
    --mode jax

The --mode flag selects the transformation target:

Mode Output file suffix Description
jax _jax.py XLA-compiled JAX module (default)
fwd _d.py Scaffolded for forward-mode differentiation
bwd _d.py Scaffolded for reverse-mode differentiation with checkpointing

The --vectorize option specifies the lower-bound loops that the user wants to vectorize. By default it's set to ["kjpindex"]

Version and help:

fgpt --version      # show version information
fgpt --help         # show available commands
fgpt isolate --help # show all isolate flags
fgpt autodiff --help # show all autodiff flags

JAX conversion

from fgpt.autodiff import AutoDiff

autodiff = AutoDiff(config_path="template.yaml", mode="jax")

autodiff.transform(
    class_file="hydrol/hydrol_soil/global_module_hydrol_soil.py",
    main_file="hydrol/hydrol_soil/main_hydrol_soil.py",
)
# produces global_module_hydrol_soil_jax.py and main_hydrol_soil_jax.py

The isolate command can perform the complete pipeline, including the JAX conversion. Alternatively, it can be used to execute only stages 1 and 2, with the autodiff command handling the final stage.

Notebooks

The repository includes several example notebooks, such as Test_F2NP.ipynb and Test_JAX_Converter.ipynb, which demonstrate different features and workflows.

Before using the notebooks, complete the steps described in the Installation section. Then activate the virtual environment and register it as a Jupyter kernel:

source .venv/bin/activate
uv run ipython kernel install --user \
    --env VIRTUAL_ENV "$(pwd)/.venv" \
    --name=project

Once the kernel has been installed, you can launch JupyterLab with:

uv run --with jupyter jupyter lab

Alternatively, you can open the notebooks directly in Visual Studio Code. VS Code will automatically detect the project's .venv. Simply select the project kernel (or the corresponding virtual environment) when prompted.


Testing

FGPT uses pytest for comprehensive testing of the transpilation pipeline, metadata extraction, JAX conversion, and the futur automatic differentiation workflows.

# Full test suite
pytest tests/ -v

# Specific module
pytest tests/test_f2np.py -v
pytest tests/test_transformer.py -v
pytest tests/test_autodiff.py -v

# Specific class or test
pytest tests/test_autodiff.py::TestAutoDiff -v
pytest tests/test_autodiff.py::TestAutoDiff::test_add_jax_imports -v

# Coverage report
pytest --cov=fgpt --cov-report=term-missing

Development

# Install pre-commit hooks
pre-commit install

# Run on all files
pre-commit run --all-files

License

This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

You are free to share and adapt the material under the following terms: Attribution, NonCommercial, and ShareAlike. See the LICENSE file for full details.


Authors

Kazem Ardaneh CNRS / IPSL / Sorbonne University kardaneh@ipsl.fr

Shivamshan Sivanesan CNRS / IPSL ssivanesan@ipsl.fr

Citation

If you use FGPT in your research, please cite the software.

BibTeX

@software{ardaneh_fgpt_2026,
  author = {Kazem Ardaneh and Shivamshan Sivanesan},
  title = {FGPT: A Fortran-to-Python and JAX Transpiler for Scientific Codes},
  year = {2026},
  publisher = {GitHub},
  url = {https://github.com/kardaneh/IPSL-FGPT}
}

About

AST-based transpiler that converts production scientific Fortran into NumPy Python and optional JAX/Equinox modules for GPU acceleration and automatic differentiation.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages