brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
fortranBest practices for modern Fortran (2003/2008+) scientific and numerical computing, covering modules, explicit interfaces, kind parameters, memory safety, and testing. Use when writing or reviewing Fortran source (.f90/.f95/.f03/.f08), defining modules and derived types, choosing numeric kind parameters, working with allocatable arrays, setting up a Fortran …
Independent GitHub snapshot · Automated classification · Original documentation governs
This skill covers writing modern, maintainable Fortran (2003/2008 and later) for scientific and numerical computing, including module organization, kind parameters, procedure design, memory safety, and testing.
kinds_mod (or similarly named) module with iso_fortran_env or selected_real_kind/selected_int_kind parameters used across the whole project.implicit none at the top.intent(in), intent(out), or intent(inout); use use, only: to import exactly what's needed.allocated() before use, and deallocate when the lifetime isn't naturally scoped.-Wall -Wextra -std=f2008 (gfortran) or the equivalent, and fail CI on new warnings.implicit none in every program unit (module, program, and — via inheritance from a module or explicit statement — every procedure) so undeclared-variable typos are caught at compile time instead of producing silent wrong answers.module linear_solver in linear_solver.f90).COMMON blocks (replace with modules), GOTO-heavy control flow (replace with structured if/do/select case, plus block where useful), and numeric statement labels used as jump targets.kind_mod or precision_mod) so the whole codebase can change precision in one place.real(kind=dp) (or the project's approved real kind) for floating-point values — never bare real or double precision, whose actual precision is compiler- and flag-dependent.integer(kind=i4) (or the project's approved integer kind) for integers where the width matters, especially in interfaces to C or binary I/O.pi explicitly and precisely (e.g., real(dp), parameter :: pi = 4.0_dp * atan(1.0_dp)) rather than truncated literals.real(dp) :: velocity ! m/s).particle_t type with position, velocity, and mass fields) instead of passing many loose primitive arguments through procedure calls.module kinds_mod
use iso_fortran_env, only: real64, int32
implicit none
private
public :: dp, i4
integer, parameter :: dp = real64
integer, parameter :: i4 = int32
end module kinds_mod
module stats_mod
use kinds_mod, only: dp
implicit none
private
public :: mean, standard_deviation
contains
pure function mean(x) result(m)
real(dp), intent(in) :: x(:)
real(dp) :: m
m = sum(x) / real(size(x), dp)
end function mean
pure function standard_deviation(x) result(s)
real(dp), intent(in) :: x(:)
real(dp) :: s
real(dp) :: m
integer :: n
n = size(x)
if (n < 2) then
s = 0.0_dp
return
end if
m = mean(x)
s = sqrt(sum((x - m)**2) / real(n - 1, dp))
end function standard_deviation
end module stats_mod
program demo
use kinds_mod, only: dp
use stats_mod, only: mean, standard_deviation
implicit none
real(dp) :: samples(5)
samples = [1.0_dp, 2.0_dp, 3.0_dp, 4.0_dp, 5.0_dp]
print '(A, F0.4)', 'mean = ', mean(samples)
print '(A, F0.4)', 'stddev = ', standard_deviation(samples)
end program demo
particle_velocity, not particleVelocity or ParticleVelocity).Count vs count) since Fortran treats them as identical, inviting confusion.compute_residual, not cr or calc2).end statements (end module kinds_mod, end subroutine compute_residual) so long units are easy to verify by eye.do, if, select case, and module blocks.intent(in), intent(out), or intent(inout) for every dummy argument; an argument with no intent is a red flag that the interface hasn't been thought through.pure or elemental when they qualify) and reserve subroutines for procedures that mutate state or perform I/O.if (n <= 0) then; ...; return; end if) over deeply nested if blocks.use, only: name1, name2 when importing from a module instead of a bare use module_name, so it's clear at the call site exactly what's being pulled in and name collisions are avoided.allocated() state and array sizes (size(), lbound(), ubound()) before using an array that might not have been allocated yet.real(dp) :: a(0:n)).gfortran -Wall -Wextra -std=f2008 -fcheck=all for development builds) and treat important warnings as CI failures.standard_deviation should have a small, fast test with known input/output) and integration tests for full numerical workflows.abs(actual - expected) < 1.0e-10_dp) rather than relying on exact floating-point equality, which is almost never guaranteed across compilers or optimization levels.block construct — Fortran requires all declarations before executable code in a given scoping unit.random_number is a function; it is a subroutine (call random_number(x), not x = random_number()).print, write(*,*)) from a procedure declared pure — this is not allowed and will fail to compile.pi, dp, or other project-standard kind/constant names already exist without importing or defining them explicitly via use.