Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 234 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
# CLAUDE.md
Claude Code Operating Rules for This Repository

This file defines **hard constraints** and **preferred behaviors** for Claude
working in this repository. These rules exist to protect numerical correctness,
performance, and long-term maintainability of a high-order spectral element
codebase.

Follow all rules below unless explicitly instructed otherwise by a human
maintainer.

---

## 1. Project Purpose

This project implements **high-order spectral element methods** for solving
systems of conservation laws (e.g., Euler, shallow water, Maxwell, MHD) on
structured and unstructured meshes.

Primary goals:
- Numerical correctness and stability
- Conservation properties
- High performance on CPUs and GPUs
- MPI scalability

Changes must NOT degrade:
- Accuracy order
- Stability properties
- Parallel scaling
- Memory behavior

---

## 2. Fortran Standards & Toolchain

### Language Standard
- Target: **Fortran 2008**
- Code must remain compatible with:
- gfortran ≥ 11
- ifx
- nvfortran
- amdflang

### Prohibited Language Features
Do NOT introduce:
- Coarrays
- Fortran 2018+ features
- Compiler-specific extensions
- Automatic polymorphism in performance-critical paths

### Formatting & Conventions
- Free-form source
- `implicit none` required in all program units
- Explicit `intent(in|out|inout)` on all dummy arguments
- Lowercase keywords preferred
- Line length ≤ 100 characters

---

## 3. Numerical & Algorithmic Constraints

### Hard Rules
- Do NOT change the mathematical formulation without approval
- Do NOT change discretization order
- Do NOT change basis, quadrature, or nodal ordering
- Do NOT reorder floating-point reductions
- Do NOT alter time integration schemes

### Floating-Point Behavior
- Bitwise reproducibility may be required
- Preserve operation ordering in loops
- Avoid algebraic “simplifications” unless mathematically justified

### Array Semantics
- Do NOT replace explicit loops with array syntax unless equivalence is proven
- Avoid implicit temporaries

---

## 4. Performance Rules (Critical)

This is an HPC codebase. Performance regressions are unacceptable.

### Memory
- Avoid temporary allocations in hot paths
- No automatic arrays in tight loops
- No hidden allocations via array slicing

### Loops
- Preserve loop ordering for cache locality
- Do NOT replace DO loops with WHERE / FORALL
- Vectorization-friendly structure must be preserved

### Abstraction
- Do NOT introduce runtime polymorphism in kernels
- Avoid excessive modularization inside hot loops

---

## 5. Parallel Programming

### MPI
- MPI calls must remain explicit
- Do NOT introduce blocking collectives inside time-stepping loops
- Do NOT change communicator usage
- Preserve rank-local data ownership

### OpenMP / GPU
- Preserve OpenMP semantics
- Do NOT move data regions without explicit instruction
- GPU kernels must preserve memory access patterns
- No implicit host/device transfers

---

## 6. Code Organization & APIs

### File & Module Structure
- Do NOT rename modules
- Do NOT move files between directories
- Do NOT change public interfaces without approval
- Preserve module dependency order

### Public APIs
- Public procedures are considered **stable**
- Backward compatibility is required unless stated otherwise

---

## 7. Testing & Validation

### Required
- All existing regression tests must pass
- Do NOT modify reference output files
- Numerical differences must be justified

### New Code
- New features require:
- A test case
- Clear validation criteria
- MPI tests must work on ≥ 2 ranks

---

## 8. Documentation & Comments

### Preserve Scientific Meaning
- Do NOT remove comments describing:
- Equations
- Algorithms
- Numerical assumptions

### New Routines
Must include:
- Mathematical description
- Variable meaning and units
- Expected input ranges

---

## 9. Code Formatting

All Fortran source must be formatted with [`fprettify`](https://pypi.org/project/fprettify/) using the project's `fprettify.config`. PRs are checked for formatting before any other tests run.

To format all source files manually:

```shell
fprettify './src/' --config-file ./fprettify.config --recursive --case 1 1 1 1
fprettify './test/' --config-file ./fprettify.config --recursive --case 1 1 1 1
fprettify './examples/' --config-file ./fprettify.config --recursive --case 1 1 1 1
```

Alternatively, install the provided `pre-commit` hook to apply formatting automatically on each commit:

```shell
pip install pre-commit fprettify
pre-commit install # run from repository root
```

When editing Fortran files, apply `fprettify` before committing. Do NOT manually reformat code by hand in ways that deviate from `fprettify` output.

---

## 10. Prohibited Actions (Explicit)

Do NOT:
- Rewrite code in another language
- Convert procedural code to OO Fortran
- Replace MPI with coarrays
- Introduce external dependencies
- “Modernize” syntax without benefit
- Delete legacy code without explanation

---

## 11. Domain-Specific Assumptions

- Grid indexing follows project conventions (do NOT reorder indices)
- Jacobians and metric terms are precomputed
- Flux routines assume nodal basis ordering
- Element-local operations must remain element-local
- Halo exchange patterns are fixed

---

## 12. Preferred Behavior

DO:
- Ask before changing algorithms
- Explain numerical and performance implications
- Provide minimal diffs
- Reference existing patterns in the codebase
- Flag any uncertainty explicitly

DO NOT:
- Make large refactors unless requested
- Assume intent beyond the explicit request

---

## 13. When in Doubt

If a change could affect:
- Numerical accuracy
- Stability
- Performance
- Parallel behavior

STOP and ask for clarification.

---

End of CLAUDE.md

1 change: 1 addition & 0 deletions examples/linear_euler2d_planewave_propagation.f90
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pure function hbc2d_Prescribed_lineareuler2d_planewave(this,x,t) result(exts)
exts(2) = u*shape ! u
exts(3) = v*shape ! v
exts(4) = p*shape ! pressure
if(.false.) exts(1) = exts(1)+t ! suppress unused-dummy-argument warning

endfunction hbc2d_Prescribed_lineareuler2d_planewave

Expand Down
1 change: 1 addition & 0 deletions examples/linear_euler2d_planewave_reflection.f90
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ pure function hbc2d_Prescribed_lineareuler2d_planewave(this,x,t) result(exts)
exts(2) = u*(shi-shr) ! u
exts(3) = v*(shi+shr) ! v
exts(4) = p*(shi+shr) ! pressure
if(.false.) exts(1) = exts(1)+t ! suppress unused-dummy-argument warning

endfunction hbc2d_Prescribed_lineareuler2d_planewave

Expand Down
2 changes: 0 additions & 2 deletions examples/linear_shallow_water2d_kelvinwaves.f90
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,11 @@ program linear_shallow_water2d_kelvinwaves
real(prec),parameter :: f0 = 10.0_prec ! reference coriolis parameter (1/s)
real(prec),parameter :: Cd = 0.25_prec ! Linear drag coefficient (1/s)
real(prec),parameter :: iointerval = 0.05 ! Write files 20 times per characteristic time scale
real(prec) :: r
real(prec) :: e0,ef ! Initial and final entropy
type(LinearShallowWater2D) :: modelobj ! Shallow water model
type(Lagrange),target :: interp ! Interpolant
type(Mesh2D),target :: mesh ! Mesh class
type(SEMQuad),target :: geometry ! Geometry class
integer :: i,j,iel
real(prec),parameter :: g = 1.0_prec ! Acceleration due to gravity
real(prec),parameter :: H = 1.0_prec ! Uniform resting depth
character(LEN=255) :: WORKSPACE
Expand Down
1 change: 0 additions & 1 deletion examples/linear_shallow_water2d_nonormalflow.f90
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ program linear_shallow_water2d_nonormalflow_model
integer :: bcids(1:4) ! Boundary conditions for structured mesh
type(Mesh2D),target :: mesh ! Mesh class
type(SEMQuad),target :: geometry ! Geometry class
character(LEN=255) :: WORKSPACE ! Used for file I/O

real(prec),parameter :: g = 1.0_prec ! Acceleration due to gravity
real(prec),parameter :: H = 1.0_prec ! Uniform resting depth
Expand Down
9 changes: 1 addition & 8 deletions src/SELF_DGModel1D_t.f90
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ subroutine CalculateEntropy_DGModel1D_t(this)
implicit none
class(DGModel1D_t),intent(inout) :: this
! Local
integer :: iel,i,ivar
integer :: iel,i
real(prec) :: e,s(1:this%solution%nvar),J

e = 0.0_prec
Expand All @@ -323,7 +323,6 @@ subroutine setboundarycondition_DGModel1D_t(this)
implicit none
class(DGModel1D_t),intent(inout) :: this
! local
integer :: ivar
integer :: N,nelem
real(prec) :: x

Expand Down Expand Up @@ -627,10 +626,6 @@ subroutine Read_DGModel1D_t(this,fileName)
character(*),intent(in) :: fileName
! Local
integer(HID_T) :: fileId
integer(HID_T) :: solOffset(1:3)
integer :: firstElem
integer :: N

call Open_HDF5(fileName,H5F_ACC_RDWR_F,fileId)
call ReadArray_HDF5(fileId,'/controlgrid/solution/interior',this%solution%interior)
call Close_HDF5(fileId)
Expand All @@ -643,14 +638,12 @@ subroutine WriteTecplot_DGModel1D_t(this,filename)
class(DGModel1D_t),intent(inout) :: this
character(*),intent(in),optional :: filename
! Local
character(8) :: zoneID
integer :: fUnit
integer :: iEl,i,iVar
character(LEN=self_FileNameLength) :: tecFile
character(LEN=self_TecplotHeaderLength) :: tecHeader
character(LEN=self_FormatLength) :: fmat
character(13) :: timeStampString
character(5) :: rankString
type(Scalar1D) :: solution
type(Scalar1D) :: x
type(Lagrange),target :: interp
Expand Down
6 changes: 1 addition & 5 deletions src/SELF_DGModel2D_t.f90
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@ subroutine Init_DGModel2D_t(this,mesh,geometry)
type(Mesh2D),intent(in),target :: mesh
type(SEMQuad),intent(in),target :: geometry
! Local
integer :: ivar
character(LEN=3) :: ivarChar
character(LEN=25) :: varname

this%mesh => mesh
this%geometry => geometry
call this%SetNumberOfVariables()
Expand Down Expand Up @@ -650,7 +646,7 @@ subroutine Read_DGModel2D_t(this,fileName)
integer(HID_T) :: fileId
integer(HID_T) :: solOffset(1:3)
integer :: firstElem
integer :: N,ivar
integer :: ivar

if(this%mesh%decomp%mpiEnabled) then
call Open_HDF5(fileName,H5F_ACC_RDWR_F,fileId, &
Expand Down
4 changes: 0 additions & 4 deletions src/SELF_DGModel3D_t.f90
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@ subroutine Init_DGModel3D_t(this,mesh,geometry)
type(Mesh3D),intent(in),target :: mesh
type(SEMHex),intent(in),target :: geometry
! Local
integer :: ivar
character(LEN=3) :: ivarChar
character(LEN=25) :: varname

this%mesh => mesh
this%geometry => geometry
call this%SetNumberOfVariables()
Expand Down
2 changes: 1 addition & 1 deletion src/SELF_Geometry_2D.f90
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ subroutine WriteTecplot_SEMQuad(this,filename)
! Local
character(8) :: zoneID
integer :: fUnit
integer :: iEl,i,j,iVar
integer :: iEl,i,j
character(LEN=self_TecplotHeaderLength) :: tecHeader
character(LEN=self_FormatLength) :: fmat

Expand Down
2 changes: 1 addition & 1 deletion src/SELF_Geometry_3D.f90
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ subroutine WriteTecplot_SEMHex(this,filename)
! Local
character(8) :: zoneID
integer :: fUnit
integer :: iEl,i,j,k,iVar
integer :: iEl,i,j,k
character(LEN=self_TecplotHeaderLength) :: tecHeader
character(LEN=self_FormatLength) :: fmat

Expand Down
6 changes: 3 additions & 3 deletions src/SELF_LinearEuler2D_t.f90
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,6 @@ pure function hbc2d_NoNormalFlow_LinearEuler2D_t(this,s,nhat) result(exts)
real(prec),intent(in) :: s(1:this%nvar)
real(prec),intent(in) :: nhat(1:2)
real(prec) :: exts(1:this%nvar)
! Local
integer :: ivar

exts(1) = s(1) ! density
exts(2) = (nhat(2)**2-nhat(1)**2)*s(2)-2.0_prec*nhat(1)*nhat(2)*s(3) ! u
Expand All @@ -150,6 +148,7 @@ pure function flux2d_LinearEuler2D_t(this,s,dsdx) result(flux)
flux(3,2) = s(4)/this%rho0 ! y-velocity, y flux; p/rho0
flux(4,1) = this%c*this%c*this%rho0*s(2) ! pressure, x flux : rho0*c^2*u
flux(4,2) = this%c*this%c*this%rho0*s(3) ! pressure, y flux : rho0*c^2*v
if(.false.) flux(1,1) = flux(1,1)+dsdx(1,1) ! suppress unused-dummy-argument warning

endfunction flux2d_LinearEuler2D_t

Expand Down Expand Up @@ -186,6 +185,7 @@ pure function riemannflux2d_LinearEuler2D_t(this,sL,sR,dsdx,nhat) result(flux)
fR(4) = rho0*c*c*(u*nhat(1)+v*nhat(2)) ! pressure

flux(1:4) = 0.5_prec*(fL(1:4)+fR(1:4))+c*(sL(1:4)-sR(1:4))
if(.false.) flux(1) = flux(1)+dsdx(1,1) ! suppress unused-dummy-argument warning

endfunction riemannflux2d_LinearEuler2D_t

Expand All @@ -207,7 +207,7 @@ subroutine SphericalSoundWave_LinearEuler2D_t(this,rhoprime,Lr,x0,y0)
real(prec),intent(in) :: rhoprime,Lr,x0,y0
! Local
integer :: i,j,iEl
real(prec) :: x,y,rho,r,E
real(prec) :: x,y,rho,r

print*,__FILE__," : Configuring weak blast wave initial condition. "
print*,__FILE__," : rhoprime = ",rhoprime
Expand Down
Loading