diff --git a/.cursor/rules/mfc-agent-rules.mdc b/.cursor/rules/mfc-agent-rules.mdc index a63276f493..6a8baddd64 100644 --- a/.cursor/rules/mfc-agent-rules.mdc +++ b/.cursor/rules/mfc-agent-rules.mdc @@ -1,30 +1,32 @@ ----- --description: Full MFC project rules – consolidated for Agent Mode --alwaysApply: true ----- +--- +description: Full MFC project rules – consolidated for Agent Mode +alwaysApply: true +--- # 0 Purpose & Scope -Consolidated guidance for the MFC exascale, many-physics solver. -Written primarily for Fortran/Fypp; the GPU and style sections matter only when `.fpp` / `.f90` files are in view. +Consolidated guidance for the MFC exascale, many-physics solver. +Written primarily for Fortran/Fypp; the OpenACC and style sections matter only when +`.fpp` / `.f90` files are in view. --- # 1 Global Project Context (always) -- **Project**: *MFC* is modern Fortran 2008+ generated with **Fypp**. - - Sources `src/`, tests `tests/`, examples `examples/`. - - Most sources are `.fpp`; CMake transpiles them to `.f90`. -- **Fypp macros** live in `src//include/` you should scan these first. - `` ∈ {`simulation`,`common`,`pre_process`,`post_process`}. -- Only `simulation` (+ its `common` calls) is GPU-accelerated via **OpenACC** or **OpenMP**. -- Assume free-form Fortran 2008+, `implicit none`, explicit `intent`, and modern intrinsics. -- Prefer `module … contains … subroutine foo()`; avoid `COMMON` blocks and file-level `include` files. -- **Read the full codebase and docs *before* changing code.** - - Docs: and the respository root `README.md`. +- **Project**: *MFC* is modern Fortran 2008+ generated with **Fypp**. + - Sources `src/`, tests `tests/`, examples `examples/`. + - Most sources are `.fpp`; CMake transpiles them to `.f90`. +- **Fypp macros** live in `src//include/` you should scan these first. + `` ∈ {`simulation`,`common`,`pre_process`,`post_process`}. +- Only `simulation` (+ its `common` calls) is GPU-accelerated via **OpenACC** or **OpenMP**. +- Assume free-form Fortran 2008+, `implicit none`, explicit `intent`, and modern + intrinsics. +- Prefer `module … contains … subroutine foo()`; avoid `COMMON` blocks and + file-level `include` files. +- **Read the full codebase and docs *before* changing code.** + Docs: and the respository root `README.md`. ### Incremental-change workflow - -1. Draft a step-by-step plan. -2. After each step, build: +1. Draft a step-by-step plan. +2. After each step, build: ```bash ./mfc.sh build -t pre_process simulation -j $(nproc) ``` @@ -47,10 +49,12 @@ Written primarily for Fortran/Fypp; the GPU and style sections matter only when * Subroutine → `s__` (e.g. `s_compute_flux`) * Function → `f__` * Private helpers stay in the module; avoid nested procedures. -* **Size limits**: subroutine ≤ 500 lines, helper ≤ 150, function ≤ 100, module/file ≤ 1000. -* ≤ 6 arguments per routine; otherwise pass a derived-type "params" struct. +* **Size limits**: subroutine ≤ 500 lines, helper ≤ 150, function ≤ 100, + module/file ≤ 1000. +* ≤ 6 arguments per routine; otherwise pass a derived-type “params” struct. * No `goto` (except unavoidable legacy); no global state (`COMMON`, `save`). -* Every variable: `intent(in|out|inout)` + appropriate `dimension` / `allocatable` / `pointer`. +* Every variable: `intent(in|out|inout)` + appropriate `dimension` / `allocatable` + / `pointer`. * Use `s_mpi_abort()` for errors, not `stop`. * Mark GPU-callable helpers that are called from GPU parallel loops immediately after declaration: ```fortran @@ -62,10 +66,9 @@ Written primarily for Fortran/Fypp; the GPU and style sections matter only when --- -# 3 FYPP Macros for GPU acceleration Pogramming Guidelines (for GPU kernels) +# 3 FYPP Macros for GPU acceleration Pogramming Guidelines (for kernels) -Do not directly use OpenACC or OpenMP directives directly. -Instead, use the FYPP macros contained in src/common/include/parallel_macros.fpp +Do not directly use OpenACC or OpenMP directives directly. Instead, use the FYPP macros contained in src/common/include/parallel_macros.fpp Wrap tight loops with @@ -79,100 +82,3 @@ $:GPU_PARALLEL_FOR(private='[...]', copy='[...]') * **Do not** place `stop` / `error stop` inside device code. * Must compile with Cray `ftn` and NVIDIA `nvfortran` for GPU offloading; also build CPU-only with GNU `gfortran` and Intel `ifx`/`ifort`. - ---- - -# 4 File & Module Structure - -- **File Naming**: - - `.fpp` files: Fypp preprocessed files that get translated to `.f90` - - Modules are named with `m_` prefix followed by feature name: `m_helper_basic`, `m_viscous` - - Primary program file is named `p_main.fpp` - -- **Module Layout**: - - Start with Fypp include for macros: `#:include 'macros.fpp'` - - Header comments using `!>` style documentation - - `module` declaration with name matching filename - - `use` statements for dependencies - - `implicit none` statement - - `private` declaration followed by explicit `public` exports - - `contains` section - - Implementation of subroutines and functions - -# 5 Fypp Macros and GPU Acceleration - -## Use of Fypp -- **Fypp Directives**: - - Start with `#:` (e.g., `#:include`, `#:def`, `#:enddef`) - - Macros defined in `include/*.fpp` files - - Used for code generation, conditional compilation, and GPU offloading - -## Some examples - -Documentation on how to use the Fypp macros for GPU offloading is available at https://mflowcode.github.io/documentation/md_gpuParallelization.html - -Some examples include: -- `$:GPU_ROUTINE(parallelism='[seq]')` - Marks GPU-callable routines -- `$:GPU_PARALLEL_LOOP(collapse=N)` - Parallelizes loops -- `$:GPU_LOOP(parallelism='[seq]')` - Marks sequential loops -- `$:GPU_UPDATE(device='[var1,var2]')` - Updates device data -- `$:GPU_ENTER_DATA(copyin='[var]')` - Copies data to device -- `$:GPU_EXIT_DATA(delete='[var]')` - Removes data from device - -# 6 Documentation Style - -- **Subroutine/Function Documentation**: - ```fortran - !> This procedure - !! @param param_name Description of the parameter - !! @return Description of the return value (for functions) - ``` -which conforms to the Doxygen Fortran format. - -# 7 Error Handling - -- **Assertions**: - - Use the fypp `ASSERT` macro for validating conditions - - Example: `@:ASSERT(predicate, message)` - -- **Error Reporting**: - - Use `s_mpi_abort()` for error termination, not `stop` - - No `stop` / `error stop` inside device code - -# 8 Memory Management - -- **Allocation/Deallocation**: - - Use fypp macro `@:ALLOCATE(var1, var2)` macro for device-aware allocation - - Use fypp macro `@:DEALLOCATE(var1, var2)` macro for device-aware deallocation - -# 9. Additional Observed Patterns - -- **Derived Types**: - - Extensive use of derived types for encapsulation - - Use pointers within derived types (e.g., `pointer, dimension(:,:,:) => null()`) - - Clear documentation of derived type components - -- **Pure & Elemental Functions**: - - Use `pure` and `elemental` attributes for side-effect-free functions - - Combine them for operations on arrays (`pure elemental function`) - -- **Precision Handling**: - - Use `wp` (working precision) parameter from `m_precision_select` - - Never hardcode precision with `real*8` or similar - -- **Loop Optimization**: - - Favor array operations over explicit loops when possible - - Use `collapse=N` directive to optimize nested loops - -# 10. Fortran Practices to Avoid - -- **Fixed Format**: Only free-form Fortran is used - - No column-position dependent code - -- **Older Intrinsics**: Avoid outdated Fortran features like: - - `equivalence` statements - - `data` statements (use initialization expressions) - - Character*N (use `character(len=N)` instead) - -- **Using same variable for multiple purposes**: Maintain single responsibility - - Each variable should have one clear purpose