C API Baseline#

Last updated: 2026-05-26

This note records the first MuPRO C ABI skeleton, runtime bridge, runtime context skeleton, and optional FFT runtime capability. The goal is to establish a stable external boundary before Python, CLI/TUI, or solver-specific host integrations depend on internal Fortran modules.

Scope#

Implemented in PR-014:

  • Public header: library/c_api/include/mupro.h

  • Opaque runtime handle: mupro_runtime_t

  • Opaque TDGL handle: mupro_tdgl_t

  • Status object: mupro_status_t

  • Runtime create/destroy and size setup

  • TDGL create/destroy and parameter setup

  • TDGL solve function signature with pointer, shape, and stride metadata

  • C unit smoke test: unit.c_api

  • C example: examples/c_api_tdgl

Implemented in PR-015:

  • Runtime size setup now calls a Fortran bind(C) bridge into mod_base_size::size_setup.

  • Runtime size query reads back the Fortran global size state and checks it against the C handle cache.

  • Runtime MPI setup is explicit through mupro_runtime_initialize_mpi.

  • Runtime MPI query returns the rank/process discovered by Fortran mod_base_mpi::mpi_setup.

  • Runtime destroy finalizes MPI only when MuPRO initialized MPI itself; it does not call the legacy mpi_exit path because that routine stops the process.

Implemented in PR-016:

  • Added library/runtime with mod_mupro_runtime and mod_mupro_backend.

  • Added type_mupro_RuntimeContext, including size, MPI, FFT placeholder, backend, setup state, and legacy-global-state flag.

  • Added type_mupro_BackendContext with backend kind, device ID, and device-memory ownership flag.

  • Added mupro_runtime_setup, mupro_runtime_finalize, size setup/query, and MPI initialize/finalize routines.

  • Moved the C ABI Fortran bridge to call mod_mupro_runtime instead of directly owning mod_base_size and mod_base_mpi interactions.

  • Added unit.runtime for runtime context size/MPI lifecycle coverage.

Implemented in PR-017:

  • FFT is now an optional runtime capability under mod_mupro_runtime.

  • runtime_setup still does not initialize FFT by default.

  • Added mupro_runtime_setup_fft, mupro_runtime_ensure_fft, and mupro_runtime_finalize_fft.

  • Added minimal mupro_fft_finalize in L0_FFT to release the current legacy FFT plans, work buffers, and k-vector allocation.

  • unit.runtime now verifies that FFT is not set up implicitly, can be explicitly set up, can be finalized, and can be set up again.

  • Adjusted the L0_FFT include path to avoid stale per-module .mod files shadowing the main build module output.

Implemented in PR-021:

  • Added an optional TDGL C adapter compiled when MUPRO_BUILD_TDGL=ON.

  • mupro_tdgl_setup requests runtime-owned FFT setup before calling the Fortran TDGL setup path.

  • mupro_tdgl_solve calls the existing Fortran type_TDGLContext%solve path when the adapter is enabled.

  • The default build without MUPRO_BUILD_TDGL keeps the stable C skeleton and returns MUPRO_STATUS_NOT_SETUP for solve.

  • Added integration.c_api_tdgl_adapter for TDGL-enabled builds.

Non-goal for PR-014:

  • No numerical TDGL solve through C yet.

  • No direct C ABI ownership of FFT plans yet.

  • No Python binding or GPU backend.

Non-goal for PR-015:

  • No multiple-runtime support. The current bridge still writes the legacy Fortran global size/MPI state, so the process should be treated as having one active MuPRO runtime.

  • No FFT plan lifecycle ownership yet.

Non-goal for PR-016:

  • No TDGL numerical backend connection through C yet.

  • No GPU/backend dispatch implementation beyond backend metadata.

Non-goal for PR-017:

  • No C ABI FFT API surface yet; FFT remains an internal runtime capability for solver adapters.

  • No FFT algorithm change.

  • No GPU FFT backend implementation.

Non-goal for PR-021:

  • No TDGL numerical algorithm change.

  • No public C FFT API. FFT remains solver-requested through the runtime bridge.

  • No benchmark-backed production correctness claim for TDGL yet.

Status Contract#

Every C ABI function returns mupro_status_t.

The C status codes mirror the current Fortran status foundation:

Code

Meaning

MUPRO_STATUS_SUCCESS

Call succeeded.

MUPRO_STATUS_NULL_POINTER

Required pointer argument was null.

MUPRO_STATUS_INVALID_SHAPE

Shape or stride metadata is invalid.

MUPRO_STATUS_NOT_SETUP

Required runtime or solver setup is missing, or the backend is not wired yet.

MUPRO_STATUS_LICENSE

Reserved for license validation failures.

MUPRO_STATUS_NUMERICAL

Numerical or allocation failure.

MUPRO_STATUS_INVALID_ARGUMENT

Non-shape argument is invalid.

Array Layout#

TDGL field arrays use the solver’s Fortran column-major layout.

Logical shape order:

[component, z, y, x]

This matches the current Fortran TDGL fields:

real(kind=rdp) :: field(3, Rn3, Rn2, Rn1)

Strides are measured in double elements, not bytes. A contiguous Fortran field has:

shape  = [3, Rn3, Rn2, Rn1]
stride = [1, 3, 3*Rn3, 3*Rn3*Rn2]

The C mupro_tdgl_solve implementation validates pointer, shape, and stride metadata. Without MUPRO_BUILD_TDGL, it returns MUPRO_STATUS_NOT_SETUP because the TDGL backend is not present in that build. With MUPRO_BUILD_TDGL=ON, it currently requires contiguous Fortran-column-major strides and routes the call through the Fortran TDGL adapter.

Runtime Bridge#

mupro_runtime_set_size is now the C-side owner for writing the legacy Fortran global size state. It stores the requested size in the C handle and calls a narrow Fortran bridge into mod_mupro_runtime. The runtime module then calls size_setup. mupro_runtime_get_size reads the Fortran global state back through mod_mupro_runtime and fails with MUPRO_STATUS_NUMERICAL if the Fortran state no longer matches the C handle.

mupro_runtime_initialize_mpi is the C-side owner for initializing MPI through mod_mupro_runtime, which delegates to the existing mpi_setup implementation. The runtime records whether MPI was already initialized before MuPRO entered; mupro_runtime_destroy only finalizes MPI when MuPRO owns that initialization.

The current runtime context remains a compatibility adapter over legacy globals. It is suitable for one active runtime per process, not for independent concurrent runtime handles.

Optional FFT Capability#

FFT belongs to runtime ownership, but it is not a mandatory runtime resource. mupro_runtime_setup leaves context%fft%is_setup false. Spectral solvers should call mupro_runtime_setup_fft or mupro_runtime_ensure_fft when they need FFT plans; finite-difference, finite-volume, and finite-element paths should not pay this setup cost or inherit an FFT dependency unless they request it.

The current implementation wraps the existing L0_FFT global FFT state. mupro_runtime_finalize_fft releases the legacy FFT plans and arrays before MPI finalization. This is still single-runtime compatible, not independent multi-runtime FFT ownership.

TDGL C adapter setup calls the runtime FFT setup bridge lazily. This keeps finite-difference, finite-volume, finite-element, and non-spectral users from paying FFT setup cost unless a solver asks for it.

TDGL Adapter#

The TDGL adapter is build-time optional:

  • Default L0/L1 development build: C TDGL setup stores validated parameters, and solve returns MUPRO_STATUS_NOT_SETUP.

  • MUPRO_BUILD_TDGL=ON: C TDGL setup requests runtime FFT and calls Fortran TDGL setup; C TDGL solve calls Fortran TDGL solve.

The adapter uses the current legacy global runtime/FFT state. It should be treated as one active MuPRO runtime and one active TDGL adapter context per process until solver internals stop depending on global state.

The C field arrays must use:

shape  = [3, Rn3, Rn2, Rn1]
stride = [1, 3, 3*Rn3, 3*Rn3*Rn2]

G_6x6 is interpreted as a C row-major 6x6 matrix and copied into the Fortran TDGL context before setup.

Downstream Linking#

The public ABI in mupro.h is C-compatible, but the current static SDK archive contains Fortran and C++ objects. Downstream CMake consumers should enable C, CXX, and Fortran languages before find_package(mupro). The installed package now fails early if CXX is not enabled, because otherwise C-only examples can reach link time without the C++ runtime required by the expression-evaluation object code.

Next ABI Work#

The next ABI/runtime slice should add concrete MPI smoke and benchmark-linked TDGL/FFT validation before expanding broader solver coverage.