-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Open
Description
I code in Fortran for scientific research purposes, and I've put together a Fortran cursor rules. Please check and if useful, add to the list. I've shared my cursor rules on fortran-lang.discourse.group and incorporated 2 suggestions by other people:
---
description:
globs: **/*.f,**/*.f90,**/*.f95,**/*.f03,**/*.f08,**/*.for,**/*.ftn,CMakeLists.txt,*.cmake,Makefile
alwaysApply: false
---
# Fortran Programming Guidelines
## Basic Principles
- Use English for all code and documentation.
- Always declare variables with `implicit none` in every program component.
- Create necessary derived types and modules.
- Use comments to document public modules, subroutines, and functions.
- Always add last modified date and the name of the author in the documentation.
- Follow consistent indentation in control structures.
- Use structured programming techniques.
- Avoid programming tricks that subvert the intended purpose of the language.
- Do not write programs that modify themselves as they execute.
- Always declare real variables as `real(kind=dp)` with `dp` imported from a kind_mod module.
- Always declare integer variables as `real(kind=i4)` with `i4` imported from a kind_mod module.
- Always place procedures in modules for better organization and reusability.
- If kind_mod doesn't exist, create one:
!> Numerical storage size parameters for real and integer values
module kind_mod
implicit none
public
!> Single precision real numbers, 6 digits, range 10⁻³⁷ to 10³⁷-1; 32 bits
integer, parameter :: sp = selected_real_kind(6, 37)
!> Double precision real numbers, 15 digits, range 10⁻³⁰⁷ to 10³⁰⁷-1; 64 bits
integer, parameter :: dp = selected_real_kind(15, 307)
!> Quadruple precision real numbers, 33 digits, range 10⁻⁴⁹³¹ to 10⁴⁹³¹-1; 128 bits
integer, parameter :: qp = selected_real_kind(33, 4931)
!> Char length for integers, range -2⁷ to 2⁷-1; 8 bits
integer, parameter :: i1 = selected_int_kind(2)
!> Short length for integers, range -2¹⁵ to 2¹⁵-1; 16 bits
integer, parameter :: i2 = selected_int_kind(4)
!> Length of default integers, range -2³¹ to 2³¹-1; 32 bits
integer, parameter :: i4 = selected_int_kind(9)
!> Long length for integers, range -2⁶³ to 2⁶³-1; 64 bits
integer, parameter :: i8 = selected_int_kind(18)
end module kind_mod
## Nomenclature
- Use lowercase for all Fortran constructs (do, subroutine, module, etc.).
- Follow short mathematical notation for mathematical variables/functions (Ylm, Gamma, etc.).
- Use all lowercase for other names: try to keep names to one or two syllables.
- Use underscores to clarify longer names (spline_interp, stop_error, etc.).
- Avoid abbreviations that could be ambiguous (e.g., "int" could mean integration or integer).
- Variables should be defined with units specified in comments.
- Use consistent naming conventions across modules.
- Never use the same name with different uppercase/lowercase spelling in the same scope.
- Avoid using the letters O and l and the digits 0 and 1 in names where they might be confused.
## Subroutines and Functions
- Write short subroutines and functions with a single purpose.
- Name functions with a verb and something else.
- If it returns a logical value, use isX or hasX, canX, etc.
- Always use `intent` for all arguments (in, out, inout).
- Functions should have no side effects - all function arguments should be intent(in).
- Avoid nesting blocks by:
- Early checks and returns.
- Extraction to utility subroutines.
- Use a single level of abstraction.
- Use 'Javadoc'-style comments to define inputs, outputs, and purpose.
- Make all subroutines have an explicit interface (place them in modules).
## Data
- Don't abuse primitive types and encapsulate data in derived types.
- Avoid data validations in functions and use modules with internal validation.
- Prefer immutability for data.
- Use parameter for constants.
- Specify array bounds explicitly when needed.
- Use allocatable arrays rather than pointers when possible.
- Check array sizes at the beginning of subroutines if necessary.
- Never assume that pi is a built-in constant; define it explicitly.
- Never declare variables more than once.
- Never declare superfluous variables (e.g., loop indices that aren't used).
- Always declare variables before any executable code, or use block construct.
## Modules
- Modules should always have their own file.
- Related functions, subroutines, and variables should be grouped together into modules.
- Avoid using module level variables when possible.
- Always specify `use, only` when importing from another module.
- Set entities within a module to private by default.
- Explicitly declare as public any module entities that need to be accessed externally.
- Write code that compiles with gfortran -fmodule-private.
- Avoid COMMON blocks.
## Exceptions and Error Handling
- Build error checks into the program.
- Use clear error messages.
- Implement consistent error handling mechanisms.
- Consider using error codes or status variables for expected failures.
- Document error handling procedures.
## Memory Management
- Properly deallocate allocatable arrays when no longer needed.
- Check if arrays are already allocated before allocation.
- Avoid dynamic memory and pointers when possible as they make code difficult to navigate.
- Use allocatable arrays instead of pointers when feasible.
## Testing
- Write unit tests for each public subroutine and function.
- Use test doubles to simulate dependencies.
- Write integration tests for each module.
- Test boundary conditions and error cases.
## Project Structure
- Use modular architecture.
- Organize code into logical directories.
- Use a build system like CMake.
- Use namespaces (modules) to organize code logically.
- Create utility modules for common functions.
## Standard Compliance
- Follow modern Fortran standards (Fortran 2003, 2008, or newer).
- Avoid obsolete features.
- Use modern syntax when available (e.g., array constructors with square brackets).
- Avoid GOTO statements and numeric labels.
- Do not use non-standard syntax just for convenience.
## Code Formatting
- Use consistent indentation (typically 2-3 spaces).
- Indent blocks in control structures (do, if, select case).
- Use blank lines to separate related parts of a program.
- Use white space freely in statements (around delimiters).
- FORTRAN keywords must be clearly set off by a blank character.
- Indent the executable statements in a DO loop at least three spaces from the DO statement.
- All elements related to a specific level of the control structure should be aligned to the same column.
- Repeat function/subroutine/module name after `end`.
- Use `end do` and `end if` consistently.
- Variable declarations must use a double colon `::` even if no other attributes are present.
- If multiple declarations occur with the same attributes, list the attributes in the same order.
- Require that loops with cycle or exit have a construct label that is used in those statements, for clarity.
## Common LLM Mistakes to Avoid
- Do not assume pi is a built-in constant; define it explicitly in your code.
- Never declare variables after executable code without using a block construct.
- Never use print or write statements in pure procedures.
- Never use random_number in pure procedures.
- Remember that random_number is a subroutine that must be called with an argument, not a function.
- Do not declare superfluous variables such as loop indices that aren't used.
- Never declare the same variable more than once in the same scope.
- Always explicitly declare as public any module entities that need to be accessed externally.
- Never have two variables in the same scope that differ only by case (e.g., Value and value).
Metadata
Metadata
Assignees
Labels
No labels